1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.configuration;
19
20 import java.awt.Color;
21 import java.lang.reflect.Array;
22 import java.lang.reflect.Constructor;
23 import java.lang.reflect.InvocationTargetException;
24 import java.math.BigDecimal;
25 import java.math.BigInteger;
26 import java.net.InetAddress;
27 import java.net.MalformedURLException;
28 import java.net.URL;
29 import java.net.UnknownHostException;
30 import java.text.ParseException;
31 import java.text.SimpleDateFormat;
32 import java.util.ArrayList;
33 import java.util.Calendar;
34 import java.util.Collection;
35 import java.util.Date;
36 import java.util.Iterator;
37 import java.util.LinkedList;
38 import java.util.List;
39 import java.util.Locale;
40
41 import org.apache.commons.lang.BooleanUtils;
42 import org.apache.commons.lang.StringUtils;
43
44
45
46
47
48
49
50
51 public final class PropertyConverter
52 {
53
54 static final char LIST_ESC_CHAR = '\\';
55
56
57 static final String LIST_ESCAPE = String.valueOf(LIST_ESC_CHAR);
58
59
60 private static final String HEX_PREFIX = "0x";
61
62
63 private static final int HEX_RADIX = 16;
64
65
66 private static final String BIN_PREFIX = "0b";
67
68
69 private static final int BIN_RADIX = 2;
70
71
72 private static final Class<?>[] CONSTR_ARGS = {String.class};
73
74
75 private static final String INTERNET_ADDRESS_CLASSNAME = "javax.mail.internet.InternetAddress";
76
77
78
79
80 private PropertyConverter()
81 {
82
83 }
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98 static Object to(Class<?> cls, Object value, Object[] params) throws ConversionException
99 {
100 if (cls.isInstance(value))
101 {
102 return value;
103 }
104
105 if (Boolean.class.equals(cls) || Boolean.TYPE.equals(cls))
106 {
107 return toBoolean(value);
108 }
109 else if (Number.class.isAssignableFrom(cls) || cls.isPrimitive())
110 {
111 if (Integer.class.equals(cls) || Integer.TYPE.equals(cls))
112 {
113 return toInteger(value);
114 }
115 else if (Long.class.equals(cls) || Long.TYPE.equals(cls))
116 {
117 return toLong(value);
118 }
119 else if (Byte.class.equals(cls) || Byte.TYPE.equals(cls))
120 {
121 return toByte(value);
122 }
123 else if (Short.class.equals(cls) || Short.TYPE.equals(cls))
124 {
125 return toShort(value);
126 }
127 else if (Float.class.equals(cls) || Float.TYPE.equals(cls))
128 {
129 return toFloat(value);
130 }
131 else if (Double.class.equals(cls) || Double.TYPE.equals(cls))
132 {
133 return toDouble(value);
134 }
135 else if (BigInteger.class.equals(cls))
136 {
137 return toBigInteger(value);
138 }
139 else if (BigDecimal.class.equals(cls))
140 {
141 return toBigDecimal(value);
142 }
143 }
144 else if (Date.class.equals(cls))
145 {
146 return toDate(value, (String) params[0]);
147 }
148 else if (Calendar.class.equals(cls))
149 {
150 return toCalendar(value, (String) params[0]);
151 }
152 else if (URL.class.equals(cls))
153 {
154 return toURL(value);
155 }
156 else if (Locale.class.equals(cls))
157 {
158 return toLocale(value);
159 }
160 else if (isEnum(cls))
161 {
162 return convertToEnum(cls, value);
163 }
164 else if (Color.class.equals(cls))
165 {
166 return toColor(value);
167 }
168 else if (cls.getName().equals(INTERNET_ADDRESS_CLASSNAME))
169 {
170 return toInternetAddress(value);
171 }
172 else if (InetAddress.class.isAssignableFrom(cls))
173 {
174 return toInetAddress(value);
175 }
176
177 throw new ConversionException("The value '" + value + "' (" + value.getClass() + ")"
178 + " can't be converted to a " + cls.getName() + " object");
179 }
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194 public static Boolean toBoolean(Object value) throws ConversionException
195 {
196 if (value instanceof Boolean)
197 {
198 return (Boolean) value;
199 }
200 else if (value instanceof String)
201 {
202 Boolean b = BooleanUtils.toBooleanObject((String) value);
203 if (b == null)
204 {
205 throw new ConversionException("The value " + value + " can't be converted to a Boolean object");
206 }
207 return b;
208 }
209 else
210 {
211 throw new ConversionException("The value " + value + " can't be converted to a Boolean object");
212 }
213 }
214
215
216
217
218
219
220
221
222 public static Byte toByte(Object value) throws ConversionException
223 {
224 Number n = toNumber(value, Byte.class);
225 if (n instanceof Byte)
226 {
227 return (Byte) n;
228 }
229 else
230 {
231 return new Byte(n.byteValue());
232 }
233 }
234
235
236
237
238
239
240
241
242 public static Short toShort(Object value) throws ConversionException
243 {
244 Number n = toNumber(value, Short.class);
245 if (n instanceof Short)
246 {
247 return (Short) n;
248 }
249 else
250 {
251 return new Short(n.shortValue());
252 }
253 }
254
255
256
257
258
259
260
261
262 public static Integer toInteger(Object value) throws ConversionException
263 {
264 Number n = toNumber(value, Integer.class);
265 if (n instanceof Integer)
266 {
267 return (Integer) n;
268 }
269 else
270 {
271 return new Integer(n.intValue());
272 }
273 }
274
275
276
277
278
279
280
281
282 public static Long toLong(Object value) throws ConversionException
283 {
284 Number n = toNumber(value, Long.class);
285 if (n instanceof Long)
286 {
287 return (Long) n;
288 }
289 else
290 {
291 return new Long(n.longValue());
292 }
293 }
294
295
296
297
298
299
300
301
302 public static Float toFloat(Object value) throws ConversionException
303 {
304 Number n = toNumber(value, Float.class);
305 if (n instanceof Float)
306 {
307 return (Float) n;
308 }
309 else
310 {
311 return new Float(n.floatValue());
312 }
313 }
314
315
316
317
318
319
320
321
322 public static Double toDouble(Object value) throws ConversionException
323 {
324 Number n = toNumber(value, Double.class);
325 if (n instanceof Double)
326 {
327 return (Double) n;
328 }
329 else
330 {
331 return new Double(n.doubleValue());
332 }
333 }
334
335
336
337
338
339
340
341
342 public static BigInteger toBigInteger(Object value) throws ConversionException
343 {
344 Number n = toNumber(value, BigInteger.class);
345 if (n instanceof BigInteger)
346 {
347 return (BigInteger) n;
348 }
349 else
350 {
351 return BigInteger.valueOf(n.longValue());
352 }
353 }
354
355
356
357
358
359
360
361
362 public static BigDecimal toBigDecimal(Object value) throws ConversionException
363 {
364 Number n = toNumber(value, BigDecimal.class);
365 if (n instanceof BigDecimal)
366 {
367 return (BigDecimal) n;
368 }
369 else
370 {
371 return new BigDecimal(n.doubleValue());
372 }
373 }
374
375
376
377
378
379
380
381
382
383
384
385
386
387 static Number toNumber(Object value, Class<?> targetClass) throws ConversionException
388 {
389 if (value instanceof Number)
390 {
391 return (Number) value;
392 }
393 else
394 {
395 String str = value.toString();
396 if (str.startsWith(HEX_PREFIX))
397 {
398 try
399 {
400 return new BigInteger(str.substring(HEX_PREFIX.length()), HEX_RADIX);
401 }
402 catch (NumberFormatException nex)
403 {
404 throw new ConversionException("Could not convert " + str
405 + " to " + targetClass.getName()
406 + "! Invalid hex number.", nex);
407 }
408 }
409
410 if (str.startsWith(BIN_PREFIX))
411 {
412 try
413 {
414 return new BigInteger(str.substring(BIN_PREFIX.length()), BIN_RADIX);
415 }
416 catch (NumberFormatException nex)
417 {
418 throw new ConversionException("Could not convert " + str
419 + " to " + targetClass.getName()
420 + "! Invalid binary number.", nex);
421 }
422 }
423
424 try
425 {
426 Constructor<?> constr = targetClass.getConstructor(CONSTR_ARGS);
427 return (Number) constr.newInstance(new Object[]{str});
428 }
429 catch (InvocationTargetException itex)
430 {
431 throw new ConversionException("Could not convert " + str
432 + " to " + targetClass.getName(), itex
433 .getTargetException());
434 }
435 catch (Exception ex)
436 {
437
438 throw new ConversionException(
439 "Conversion error when trying to convert " + str
440 + " to " + targetClass.getName(), ex);
441 }
442 }
443 }
444
445
446
447
448
449
450
451
452 public static URL toURL(Object value) throws ConversionException
453 {
454 if (value instanceof URL)
455 {
456 return (URL) value;
457 }
458 else if (value instanceof String)
459 {
460 try
461 {
462 return new URL((String) value);
463 }
464 catch (MalformedURLException e)
465 {
466 throw new ConversionException("The value " + value + " can't be converted to an URL", e);
467 }
468 }
469 else
470 {
471 throw new ConversionException("The value " + value + " can't be converted to an URL");
472 }
473 }
474
475
476
477
478
479
480
481
482 public static Locale toLocale(Object value) throws ConversionException
483 {
484 if (value instanceof Locale)
485 {
486 return (Locale) value;
487 }
488 else if (value instanceof String)
489 {
490 List<String> elements = split((String) value, '_');
491 int size = elements.size();
492
493 if (size >= 1 && ((elements.get(0)).length() == 2 || (elements.get(0)).length() == 0))
494 {
495 String language = elements.get(0);
496 String country = (size >= 2) ? elements.get(1) : "";
497 String variant = (size >= 3) ? elements.get(2) : "";
498
499 return new Locale(language, country, variant);
500 }
501 else
502 {
503 throw new ConversionException("The value " + value + " can't be converted to a Locale");
504 }
505 }
506 else
507 {
508 throw new ConversionException("The value " + value + " can't be converted to a Locale");
509 }
510 }
511
512
513
514
515
516
517
518
519
520
521
522
523 public static List<String> split(String s, char delimiter, boolean trim)
524 {
525 if (s == null)
526 {
527 return new ArrayList<String>();
528 }
529
530 List<String> list = new ArrayList<String>();
531
532 StringBuilder token = new StringBuilder();
533 int begin = 0;
534 boolean inEscape = false;
535
536 while (begin < s.length())
537 {
538 char c = s.charAt(begin);
539 if (inEscape)
540 {
541
542
543 if (c != delimiter && c != LIST_ESC_CHAR)
544 {
545
546 token.append(LIST_ESC_CHAR);
547 }
548 token.append(c);
549 inEscape = false;
550 }
551
552 else
553 {
554 if (c == delimiter)
555 {
556
557 String t = token.toString();
558 if (trim)
559 {
560 t = t.trim();
561 }
562 list.add(t);
563 token = new StringBuilder();
564 }
565 else if (c == LIST_ESC_CHAR)
566 {
567
568 inEscape = true;
569 }
570 else
571 {
572 token.append(c);
573 }
574 }
575
576 begin++;
577 }
578
579
580 if (inEscape)
581 {
582 token.append(LIST_ESC_CHAR);
583 }
584
585 String t = token.toString();
586 if (trim)
587 {
588 t = t.trim();
589 }
590 list.add(t);
591
592 return list;
593 }
594
595
596
597
598
599
600
601
602
603 public static List<String> split(String s, char delimiter)
604 {
605 return split(s, delimiter, true);
606 }
607
608
609
610
611
612
613
614
615
616
617 public static String escapeDelimiters(String s, char delimiter)
618 {
619 String s1 = StringUtils.replace(s, LIST_ESCAPE, LIST_ESCAPE + LIST_ESCAPE);
620 return escapeListDelimiter(s1, delimiter);
621 }
622
623
624
625
626
627
628
629
630
631
632
633
634
635 public static String escapeListDelimiter(String s, char delimiter)
636 {
637 return StringUtils.replace(s, String.valueOf(delimiter), LIST_ESCAPE
638 + delimiter);
639 }
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655 public static Color toColor(Object value) throws ConversionException
656 {
657 if (value instanceof Color)
658 {
659 return (Color) value;
660 }
661 else if (value instanceof String && !StringUtils.isBlank((String) value))
662 {
663 String color = ((String) value).trim();
664
665 int[] components = new int[3];
666
667
668 int minlength = components.length * 2;
669 if (color.length() < minlength)
670 {
671 throw new ConversionException("The value " + value + " can't be converted to a Color");
672 }
673
674
675 if (color.startsWith("#"))
676 {
677 color = color.substring(1);
678 }
679
680 try
681 {
682
683 for (int i = 0; i < components.length; i++)
684 {
685 components[i] = Integer.parseInt(color.substring(2 * i, 2 * i + 2), HEX_RADIX);
686 }
687
688
689 int alpha;
690 if (color.length() >= minlength + 2)
691 {
692 alpha = Integer.parseInt(color.substring(minlength, minlength + 2), HEX_RADIX);
693 }
694 else
695 {
696 alpha = Color.black.getAlpha();
697 }
698
699 return new Color(components[0], components[1], components[2], alpha);
700 }
701 catch (Exception e)
702 {
703 throw new ConversionException("The value " + value + " can't be converted to a Color", e);
704 }
705 }
706 else
707 {
708 throw new ConversionException("The value " + value + " can't be converted to a Color");
709 }
710 }
711
712
713
714
715
716
717
718
719
720
721 static InetAddress toInetAddress(Object value) throws ConversionException
722 {
723 if (value instanceof InetAddress)
724 {
725 return (InetAddress) value;
726 }
727 else if (value instanceof String)
728 {
729 try
730 {
731 return InetAddress.getByName((String) value);
732 }
733 catch (UnknownHostException e)
734 {
735 throw new ConversionException("The value " + value + " can't be converted to a InetAddress", e);
736 }
737 }
738 else
739 {
740 throw new ConversionException("The value " + value + " can't be converted to a InetAddress");
741 }
742 }
743
744
745
746
747
748
749
750
751
752
753 static Object toInternetAddress(Object value) throws ConversionException
754 {
755 if (value.getClass().getName().equals(INTERNET_ADDRESS_CLASSNAME))
756 {
757 return value;
758 }
759 else if (value instanceof String)
760 {
761 try
762 {
763 Constructor<?> ctor = Class.forName(INTERNET_ADDRESS_CLASSNAME)
764 .getConstructor(new Class[] {String.class});
765 return ctor.newInstance(new Object[] {value});
766 }
767 catch (Exception e)
768 {
769 throw new ConversionException("The value " + value + " can't be converted to a InternetAddress", e);
770 }
771 }
772 else
773 {
774 throw new ConversionException("The value " + value + " can't be converted to a InternetAddress");
775 }
776 }
777
778
779
780
781 static boolean isEnum(Class<?> cls)
782 {
783 return cls.isEnum();
784 }
785
786
787
788
789
790
791
792
793
794
795
796 static <E extends Enum<E>> E toEnum(Object value, Class<E> cls) throws ConversionException
797 {
798 if (value.getClass().equals(cls))
799 {
800 return cls.cast(value);
801 }
802 else if (value instanceof String)
803 {
804 try
805 {
806 return Enum.valueOf(cls, (String) value);
807 }
808 catch (Exception e)
809 {
810 throw new ConversionException("The value " + value + " can't be converted to a " + cls.getName());
811 }
812 }
813 else if (value instanceof Number)
814 {
815 try
816 {
817 E[] enumConstants = cls.getEnumConstants();
818 return enumConstants[((Number) value).intValue()];
819 }
820 catch (Exception e)
821 {
822 throw new ConversionException("The value " + value + " can't be converted to a " + cls.getName());
823 }
824 }
825 else
826 {
827 throw new ConversionException("The value " + value + " can't be converted to a " + cls.getName());
828 }
829 }
830
831
832
833
834
835
836
837
838
839 public static Date toDate(Object value, String format) throws ConversionException
840 {
841 if (value instanceof Date)
842 {
843 return (Date) value;
844 }
845 else if (value instanceof Calendar)
846 {
847 return ((Calendar) value).getTime();
848 }
849 else if (value instanceof String)
850 {
851 try
852 {
853 return new SimpleDateFormat(format).parse((String) value);
854 }
855 catch (ParseException e)
856 {
857 throw new ConversionException("The value " + value + " can't be converted to a Date", e);
858 }
859 }
860 else
861 {
862 throw new ConversionException("The value " + value + " can't be converted to a Date");
863 }
864 }
865
866
867
868
869
870
871
872
873
874 public static Calendar toCalendar(Object value, String format) throws ConversionException
875 {
876 if (value instanceof Calendar)
877 {
878 return (Calendar) value;
879 }
880 else if (value instanceof Date)
881 {
882 Calendar calendar = Calendar.getInstance();
883 calendar.setTime((Date) value);
884 return calendar;
885 }
886 else if (value instanceof String)
887 {
888 try
889 {
890 Calendar calendar = Calendar.getInstance();
891 calendar.setTime(new SimpleDateFormat(format).parse((String) value));
892 return calendar;
893 }
894 catch (ParseException e)
895 {
896 throw new ConversionException("The value " + value + " can't be converted to a Calendar", e);
897 }
898 }
899 else
900 {
901 throw new ConversionException("The value " + value + " can't be converted to a Calendar");
902 }
903 }
904
905
906
907
908
909
910
911
912
913
914 public static Iterator<?> toIterator(Object value, char delimiter)
915 {
916 return flatten(value, delimiter).iterator();
917 }
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942 private static Collection<?> flatten(Object value, char delimiter)
943 {
944 if (value instanceof String)
945 {
946 String s = (String) value;
947 if (s.indexOf(delimiter) > 0)
948 {
949 return split(s, delimiter);
950 }
951 }
952
953 Collection<Object> result = new LinkedList<Object>();
954 if (value instanceof Iterable)
955 {
956 flattenIterator(result, ((Iterable<?>) value).iterator(), delimiter);
957 }
958 else if (value instanceof Iterator)
959 {
960 flattenIterator(result, (Iterator<?>) value, delimiter);
961 }
962 else if (value != null)
963 {
964 if (value.getClass().isArray())
965 {
966 for (int len = Array.getLength(value), idx = 0; idx < len; idx++)
967 {
968 result.addAll(flatten(Array.get(value, idx), delimiter));
969 }
970 }
971 else
972 {
973 result.add(value);
974 }
975 }
976
977 return result;
978 }
979
980
981
982
983
984
985
986
987
988 private static void flattenIterator(Collection<Object> target, Iterator<?> it, char delimiter)
989 {
990 while (it.hasNext())
991 {
992 target.addAll(flatten(it.next(), delimiter));
993 }
994 }
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006 public static Object interpolate(Object value, AbstractConfiguration config)
1007 {
1008 if (value instanceof String)
1009 {
1010 return config.getSubstitutor().replace((String) value);
1011 }
1012 else
1013 {
1014 return value;
1015 }
1016 }
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026 @SuppressWarnings("unchecked")
1027
1028 private static Object convertToEnum(Class<?> enumClass, Object value)
1029 {
1030 return toEnum(value, enumClass.asSubclass(Enum.class));
1031 }
1032 }