1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.beanutils;
19
20
21 import java.beans.IndexedPropertyDescriptor;
22 import java.beans.IntrospectionException;
23 import java.beans.Introspector;
24 import java.beans.PropertyDescriptor;
25 import java.lang.reflect.Array;
26 import java.lang.reflect.InvocationTargetException;
27 import java.lang.reflect.Method;
28 import java.util.HashMap;
29 import java.util.Iterator;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Map.Entry;
33 import java.util.concurrent.CopyOnWriteArrayList;
34
35 import org.apache.commons.beanutils.expression.DefaultResolver;
36 import org.apache.commons.beanutils.expression.Resolver;
37 import org.apache.commons.collections.FastHashMap;
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96 public class PropertyUtilsBean {
97
98 private Resolver resolver = new DefaultResolver();
99
100
101
102
103
104
105
106 protected static PropertyUtilsBean getInstance() {
107 return BeanUtilsBean.getInstance().getPropertyUtils();
108 }
109
110
111
112
113
114
115
116 private WeakFastHashMap<Class<?>, BeanIntrospectionData> descriptorsCache = null;
117 private WeakFastHashMap<Class<?>, FastHashMap> mappedDescriptorsCache = null;
118
119
120 private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
121
122
123 private final Log log = LogFactory.getLog(PropertyUtils.class);
124
125
126 private final List<BeanIntrospector> introspectors;
127
128
129
130
131 public PropertyUtilsBean() {
132 descriptorsCache = new WeakFastHashMap<Class<?>, BeanIntrospectionData>();
133 descriptorsCache.setFast(true);
134 mappedDescriptorsCache = new WeakFastHashMap<Class<?>, FastHashMap>();
135 mappedDescriptorsCache.setFast(true);
136 introspectors = new CopyOnWriteArrayList<BeanIntrospector>();
137 resetBeanIntrospectors();
138 }
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157 public Resolver getResolver() {
158 return resolver;
159 }
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174 public void setResolver(final Resolver resolver) {
175 if (resolver == null) {
176 this.resolver = new DefaultResolver();
177 } else {
178 this.resolver = resolver;
179 }
180 }
181
182
183
184
185
186
187
188 public final void resetBeanIntrospectors() {
189 introspectors.clear();
190 introspectors.add(DefaultBeanIntrospector.INSTANCE);
191 introspectors.add(SuppressPropertiesBeanIntrospector.SUPPRESS_CLASS);
192 }
193
194
195
196
197
198
199
200
201
202
203 public void addBeanIntrospector(final BeanIntrospector introspector) {
204 if (introspector == null) {
205 throw new IllegalArgumentException(
206 "BeanIntrospector must not be null!");
207 }
208 introspectors.add(introspector);
209 }
210
211
212
213
214
215
216
217
218
219 public boolean removeBeanIntrospector(final BeanIntrospector introspector) {
220 return introspectors.remove(introspector);
221 }
222
223
224
225
226
227
228 public void clearDescriptors() {
229
230 descriptorsCache.clear();
231 mappedDescriptorsCache.clear();
232 Introspector.flushCaches();
233
234 }
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268 public void copyProperties(final Object dest, final Object orig)
269 throws IllegalAccessException, InvocationTargetException,
270 NoSuchMethodException {
271
272 if (dest == null) {
273 throw new IllegalArgumentException
274 ("No destination bean specified");
275 }
276 if (orig == null) {
277 throw new IllegalArgumentException("No origin bean specified");
278 }
279
280 if (orig instanceof DynaBean) {
281 final DynaProperty[] origDescriptors =
282 ((DynaBean) orig).getDynaClass().getDynaProperties();
283 for (DynaProperty origDescriptor : origDescriptors) {
284 final String name = origDescriptor.getName();
285 if (isReadable(orig, name) && isWriteable(dest, name)) {
286 try {
287 final Object value = ((DynaBean) orig).get(name);
288 if (dest instanceof DynaBean) {
289 ((DynaBean) dest).set(name, value);
290 } else {
291 setSimpleProperty(dest, name, value);
292 }
293 } catch (final NoSuchMethodException e) {
294 if (log.isDebugEnabled()) {
295 log.debug("Error writing to '" + name + "' on class '" + dest.getClass() + "'", e);
296 }
297 }
298 }
299 }
300 } else if (orig instanceof Map) {
301 final Iterator<?> entries = ((Map<?, ?>) orig).entrySet().iterator();
302 while (entries.hasNext()) {
303 final Map.Entry<?, ?> entry = (Entry<?, ?>) entries.next();
304 final String name = (String)entry.getKey();
305 if (isWriteable(dest, name)) {
306 try {
307 if (dest instanceof DynaBean) {
308 ((DynaBean) dest).set(name, entry.getValue());
309 } else {
310 setSimpleProperty(dest, name, entry.getValue());
311 }
312 } catch (final NoSuchMethodException e) {
313 if (log.isDebugEnabled()) {
314 log.debug("Error writing to '" + name + "' on class '" + dest.getClass() + "'", e);
315 }
316 }
317 }
318 }
319 } else {
320 final PropertyDescriptor[] origDescriptors =
321 getPropertyDescriptors(orig);
322 for (PropertyDescriptor origDescriptor : origDescriptors) {
323 final String name = origDescriptor.getName();
324 if (isReadable(orig, name) && isWriteable(dest, name)) {
325 try {
326 final Object value = getSimpleProperty(orig, name);
327 if (dest instanceof DynaBean) {
328 ((DynaBean) dest).set(name, value);
329 } else {
330 setSimpleProperty(dest, name, value);
331 }
332 } catch (final NoSuchMethodException e) {
333 if (log.isDebugEnabled()) {
334 log.debug("Error writing to '" + name + "' on class '" + dest.getClass() + "'", e);
335 }
336 }
337 }
338 }
339 }
340
341 }
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363 public Map<String, Object> describe(final Object bean)
364 throws IllegalAccessException, InvocationTargetException,
365 NoSuchMethodException {
366
367 if (bean == null) {
368 throw new IllegalArgumentException("No bean specified");
369 }
370 final Map<String, Object> description = new HashMap<String, Object>();
371 if (bean instanceof DynaBean) {
372 final DynaProperty[] descriptors =
373 ((DynaBean) bean).getDynaClass().getDynaProperties();
374 for (DynaProperty descriptor : descriptors) {
375 final String name = descriptor.getName();
376 description.put(name, getProperty(bean, name));
377 }
378 } else {
379 final PropertyDescriptor[] descriptors =
380 getPropertyDescriptors(bean);
381 for (PropertyDescriptor descriptor : descriptors) {
382 final String name = descriptor.getName();
383 if (descriptor.getReadMethod() != null) {
384 description.put(name, getProperty(bean, name));
385 }
386 }
387 }
388 return (description);
389
390 }
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417 public Object getIndexedProperty(final Object bean, String name)
418 throws IllegalAccessException, InvocationTargetException,
419 NoSuchMethodException {
420
421 if (bean == null) {
422 throw new IllegalArgumentException("No bean specified");
423 }
424 if (name == null) {
425 throw new IllegalArgumentException("No name specified for bean class '" +
426 bean.getClass() + "'");
427 }
428
429
430 int index = -1;
431 try {
432 index = resolver.getIndex(name);
433 } catch (final IllegalArgumentException e) {
434 throw new IllegalArgumentException("Invalid indexed property '" +
435 name + "' on bean class '" + bean.getClass() + "' " +
436 e.getMessage());
437 }
438 if (index < 0) {
439 throw new IllegalArgumentException("Invalid indexed property '" +
440 name + "' on bean class '" + bean.getClass() + "'");
441 }
442
443
444 name = resolver.getProperty(name);
445
446
447 return (getIndexedProperty(bean, name, index));
448
449 }
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474 public Object getIndexedProperty(final Object bean,
475 final String name, final int index)
476 throws IllegalAccessException, InvocationTargetException,
477 NoSuchMethodException {
478
479 if (bean == null) {
480 throw new IllegalArgumentException("No bean specified");
481 }
482 if (name == null || name.length() == 0) {
483 if (bean.getClass().isArray()) {
484 return Array.get(bean, index);
485 } else if (bean instanceof List) {
486 return ((List<?>)bean).get(index);
487 }
488 }
489 if (name == null) {
490 throw new IllegalArgumentException("No name specified for bean class '" +
491 bean.getClass() + "'");
492 }
493
494
495 if (bean instanceof DynaBean) {
496 final DynaProperty descriptor =
497 ((DynaBean) bean).getDynaClass().getDynaProperty(name);
498 if (descriptor == null) {
499 throw new NoSuchMethodException("Unknown property '" +
500 name + "' on bean class '" + bean.getClass() + "'");
501 }
502 return (((DynaBean) bean).get(name, index));
503 }
504
505
506 final PropertyDescriptor descriptor =
507 getPropertyDescriptor(bean, name);
508 if (descriptor == null) {
509 throw new NoSuchMethodException("Unknown property '" +
510 name + "' on bean class '" + bean.getClass() + "'");
511 }
512
513
514 if (descriptor instanceof IndexedPropertyDescriptor) {
515 Method readMethod = ((IndexedPropertyDescriptor) descriptor).
516 getIndexedReadMethod();
517 readMethod = MethodUtils.getAccessibleMethod(bean.getClass(), readMethod);
518 if (readMethod != null) {
519 final Object[] subscript = new Object[1];
520 subscript[0] = new Integer(index);
521 try {
522 return (invokeMethod(readMethod,bean, subscript));
523 } catch (final InvocationTargetException e) {
524 if (e.getTargetException() instanceof
525 IndexOutOfBoundsException) {
526 throw (IndexOutOfBoundsException)
527 e.getTargetException();
528 } else {
529 throw e;
530 }
531 }
532 }
533 }
534
535
536 final Method readMethod = getReadMethod(bean.getClass(), descriptor);
537 if (readMethod == null) {
538 throw new NoSuchMethodException("Property '" + name + "' has no " +
539 "getter method on bean class '" + bean.getClass() + "'");
540 }
541
542
543 final Object value = invokeMethod(readMethod, bean, EMPTY_OBJECT_ARRAY);
544 if (!value.getClass().isArray()) {
545 if (!(value instanceof java.util.List)) {
546 throw new IllegalArgumentException("Property '" + name +
547 "' is not indexed on bean class '" + bean.getClass() + "'");
548 } else {
549
550 return ((java.util.List<?>) value).get(index);
551 }
552 } else {
553
554 try {
555 return (Array.get(value, index));
556 } catch (final ArrayIndexOutOfBoundsException e) {
557 throw new ArrayIndexOutOfBoundsException("Index: " +
558 index + ", Size: " + Array.getLength(value) +
559 " for property '" + name + "'");
560 }
561 }
562
563 }
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585 public Object getMappedProperty(final Object bean, String name)
586 throws IllegalAccessException, InvocationTargetException,
587 NoSuchMethodException {
588
589 if (bean == null) {
590 throw new IllegalArgumentException("No bean specified");
591 }
592 if (name == null) {
593 throw new IllegalArgumentException("No name specified for bean class '" +
594 bean.getClass() + "'");
595 }
596
597
598 String key = null;
599 try {
600 key = resolver.getKey(name);
601 } catch (final IllegalArgumentException e) {
602 throw new IllegalArgumentException
603 ("Invalid mapped property '" + name +
604 "' on bean class '" + bean.getClass() + "' " + e.getMessage());
605 }
606 if (key == null) {
607 throw new IllegalArgumentException("Invalid mapped property '" +
608 name + "' on bean class '" + bean.getClass() + "'");
609 }
610
611
612 name = resolver.getProperty(name);
613
614
615 return (getMappedProperty(bean, name, key));
616
617 }
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636 public Object getMappedProperty(final Object bean,
637 final String name, final String key)
638 throws IllegalAccessException, InvocationTargetException,
639 NoSuchMethodException {
640
641 if (bean == null) {
642 throw new IllegalArgumentException("No bean specified");
643 }
644 if (name == null) {
645 throw new IllegalArgumentException("No name specified for bean class '" +
646 bean.getClass() + "'");
647 }
648 if (key == null) {
649 throw new IllegalArgumentException("No key specified for property '" +
650 name + "' on bean class " + bean.getClass() + "'");
651 }
652
653
654 if (bean instanceof DynaBean) {
655 final DynaProperty descriptor =
656 ((DynaBean) bean).getDynaClass().getDynaProperty(name);
657 if (descriptor == null) {
658 throw new NoSuchMethodException("Unknown property '" +
659 name + "'+ on bean class '" + bean.getClass() + "'");
660 }
661 return (((DynaBean) bean).get(name, key));
662 }
663
664 Object result = null;
665
666
667 final PropertyDescriptor descriptor = getPropertyDescriptor(bean, name);
668 if (descriptor == null) {
669 throw new NoSuchMethodException("Unknown property '" +
670 name + "'+ on bean class '" + bean.getClass() + "'");
671 }
672
673 if (descriptor instanceof MappedPropertyDescriptor) {
674
675 Method readMethod = ((MappedPropertyDescriptor) descriptor).
676 getMappedReadMethod();
677 readMethod = MethodUtils.getAccessibleMethod(bean.getClass(), readMethod);
678 if (readMethod != null) {
679 final Object[] keyArray = new Object[1];
680 keyArray[0] = key;
681 result = invokeMethod(readMethod, bean, keyArray);
682 } else {
683 throw new NoSuchMethodException("Property '" + name +
684 "' has no mapped getter method on bean class '" +
685 bean.getClass() + "'");
686 }
687 } else {
688
689 final Method readMethod = getReadMethod(bean.getClass(), descriptor);
690 if (readMethod != null) {
691 final Object invokeResult = invokeMethod(readMethod, bean, EMPTY_OBJECT_ARRAY);
692
693 if (invokeResult instanceof java.util.Map) {
694 result = ((java.util.Map<?, ?>)invokeResult).get(key);
695 }
696 } else {
697 throw new NoSuchMethodException("Property '" + name +
698 "' has no mapped getter method on bean class '" +
699 bean.getClass() + "'");
700 }
701 }
702 return result;
703
704 }
705
706
707
708
709
710
711
712
713
714
715
716 @Deprecated
717 public FastHashMap getMappedPropertyDescriptors(final Class<?> beanClass) {
718
719 if (beanClass == null) {
720 return null;
721 }
722
723
724 return mappedDescriptorsCache.get(beanClass);
725
726 }
727
728
729
730
731
732
733
734
735
736
737
738 @Deprecated
739 public FastHashMap getMappedPropertyDescriptors(final Object bean) {
740
741 if (bean == null) {
742 return null;
743 }
744 return (getMappedPropertyDescriptors(bean.getClass()));
745
746 }
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768 public Object getNestedProperty(Object bean, String name)
769 throws IllegalAccessException, InvocationTargetException,
770 NoSuchMethodException {
771
772 if (bean == null) {
773 throw new IllegalArgumentException("No bean specified");
774 }
775 if (name == null) {
776 throw new IllegalArgumentException("No name specified for bean class '" +
777 bean.getClass() + "'");
778 }
779
780
781 while (resolver.hasNested(name)) {
782 final String next = resolver.next(name);
783 Object nestedBean = null;
784 if (bean instanceof Map) {
785 nestedBean = getPropertyOfMapBean((Map<?, ?>) bean, next);
786 } else if (resolver.isMapped(next)) {
787 nestedBean = getMappedProperty(bean, next);
788 } else if (resolver.isIndexed(next)) {
789 nestedBean = getIndexedProperty(bean, next);
790 } else {
791 nestedBean = getSimpleProperty(bean, next);
792 }
793 if (nestedBean == null) {
794 throw new NestedNullException
795 ("Null property value for '" + name +
796 "' on bean class '" + bean.getClass() + "'");
797 }
798 bean = nestedBean;
799 name = resolver.remove(name);
800 }
801
802 if (bean instanceof Map) {
803 bean = getPropertyOfMapBean((Map<?, ?>) bean, name);
804 } else if (resolver.isMapped(name)) {
805 bean = getMappedProperty(bean, name);
806 } else if (resolver.isIndexed(name)) {
807 bean = getIndexedProperty(bean, name);
808 } else {
809 bean = getSimpleProperty(bean, name);
810 }
811 return bean;
812
813 }
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839 protected Object getPropertyOfMapBean(final Map<?, ?> bean, String propertyName)
840 throws IllegalArgumentException, IllegalAccessException,
841 InvocationTargetException, NoSuchMethodException {
842
843 if (resolver.isMapped(propertyName)) {
844 final String name = resolver.getProperty(propertyName);
845 if (name == null || name.length() == 0) {
846 propertyName = resolver.getKey(propertyName);
847 }
848 }
849
850 if (resolver.isIndexed(propertyName) ||
851 resolver.isMapped(propertyName)) {
852 throw new IllegalArgumentException(
853 "Indexed or mapped properties are not supported on"
854 + " objects of type Map: " + propertyName);
855 }
856
857 return bean.get(propertyName);
858 }
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881 public Object getProperty(final Object bean, final String name)
882 throws IllegalAccessException, InvocationTargetException,
883 NoSuchMethodException {
884
885 return (getNestedProperty(bean, name));
886
887 }
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920 public PropertyDescriptor getPropertyDescriptor(Object bean,
921 String name)
922 throws IllegalAccessException, InvocationTargetException,
923 NoSuchMethodException {
924
925 if (bean == null) {
926 throw new IllegalArgumentException("No bean specified");
927 }
928 if (name == null) {
929 throw new IllegalArgumentException("No name specified for bean class '" +
930 bean.getClass() + "'");
931 }
932
933
934 while (resolver.hasNested(name)) {
935 final String next = resolver.next(name);
936 final Object nestedBean = getProperty(bean, next);
937 if (nestedBean == null) {
938 throw new NestedNullException
939 ("Null property value for '" + next +
940 "' on bean class '" + bean.getClass() + "'");
941 }
942 bean = nestedBean;
943 name = resolver.remove(name);
944 }
945
946
947 name = resolver.getProperty(name);
948
949
950
951 if (name == null) {
952 return (null);
953 }
954
955 final BeanIntrospectionData data = getIntrospectionData(bean.getClass());
956 PropertyDescriptor result = data.getDescriptor(name);
957 if (result != null) {
958 return result;
959 }
960
961 FastHashMap mappedDescriptors =
962 getMappedPropertyDescriptors(bean);
963 if (mappedDescriptors == null) {
964 mappedDescriptors = new FastHashMap();
965 mappedDescriptors.setFast(true);
966 mappedDescriptorsCache.put(bean.getClass(), mappedDescriptors);
967 }
968 result = (PropertyDescriptor) mappedDescriptors.get(name);
969 if (result == null) {
970
971 try {
972 result = new MappedPropertyDescriptor(name, bean.getClass());
973 } catch (final IntrospectionException ie) {
974
975
976
977 }
978 if (result != null) {
979 mappedDescriptors.put(name, result);
980 }
981 }
982
983 return result;
984
985 }
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000 public PropertyDescriptor[]
1001 getPropertyDescriptors(final Class<?> beanClass) {
1002
1003 return getIntrospectionData(beanClass).getDescriptors();
1004
1005 }
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019 public PropertyDescriptor[] getPropertyDescriptors(final Object bean) {
1020
1021 if (bean == null) {
1022 throw new IllegalArgumentException("No bean specified");
1023 }
1024 return (getPropertyDescriptors(bean.getClass()));
1025
1026 }
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059 public Class<?> getPropertyEditorClass(final Object bean, final String name)
1060 throws IllegalAccessException, InvocationTargetException,
1061 NoSuchMethodException {
1062
1063 if (bean == null) {
1064 throw new IllegalArgumentException("No bean specified");
1065 }
1066 if (name == null) {
1067 throw new IllegalArgumentException("No name specified for bean class '" +
1068 bean.getClass() + "'");
1069 }
1070
1071 final PropertyDescriptor descriptor =
1072 getPropertyDescriptor(bean, name);
1073 if (descriptor != null) {
1074 return (descriptor.getPropertyEditorClass());
1075 } else {
1076 return (null);
1077 }
1078
1079 }
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114 public Class<?> getPropertyType(Object bean, String name)
1115 throws IllegalAccessException, InvocationTargetException,
1116 NoSuchMethodException {
1117
1118 if (bean == null) {
1119 throw new IllegalArgumentException("No bean specified");
1120 }
1121 if (name == null) {
1122 throw new IllegalArgumentException("No name specified for bean class '" +
1123 bean.getClass() + "'");
1124 }
1125
1126
1127 while (resolver.hasNested(name)) {
1128 final String next = resolver.next(name);
1129 final Object nestedBean = getProperty(bean, next);
1130 if (nestedBean == null) {
1131 throw new NestedNullException
1132 ("Null property value for '" + next +
1133 "' on bean class '" + bean.getClass() + "'");
1134 }
1135 bean = nestedBean;
1136 name = resolver.remove(name);
1137 }
1138
1139
1140 name = resolver.getProperty(name);
1141
1142
1143 if (bean instanceof DynaBean) {
1144 final DynaProperty descriptor =
1145 ((DynaBean) bean).getDynaClass().getDynaProperty(name);
1146 if (descriptor == null) {
1147 return (null);
1148 }
1149 final Class<?> type = descriptor.getType();
1150 if (type == null) {
1151 return (null);
1152 } else if (type.isArray()) {
1153 return (type.getComponentType());
1154 } else {
1155 return (type);
1156 }
1157 }
1158
1159 final PropertyDescriptor descriptor =
1160 getPropertyDescriptor(bean, name);
1161 if (descriptor == null) {
1162 return (null);
1163 } else if (descriptor instanceof IndexedPropertyDescriptor) {
1164 return (((IndexedPropertyDescriptor) descriptor).
1165 getIndexedPropertyType());
1166 } else if (descriptor instanceof MappedPropertyDescriptor) {
1167 return (((MappedPropertyDescriptor) descriptor).
1168 getMappedPropertyType());
1169 } else {
1170 return (descriptor.getPropertyType());
1171 }
1172
1173 }
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185 public Method getReadMethod(final PropertyDescriptor descriptor) {
1186
1187 return (MethodUtils.getAccessibleMethod(descriptor.getReadMethod()));
1188
1189 }
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202 Method getReadMethod(final Class<?> clazz, final PropertyDescriptor descriptor) {
1203 return (MethodUtils.getAccessibleMethod(clazz, descriptor.getReadMethod()));
1204 }
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226 public Object getSimpleProperty(final Object bean, final String name)
1227 throws IllegalAccessException, InvocationTargetException,
1228 NoSuchMethodException {
1229
1230 if (bean == null) {
1231 throw new IllegalArgumentException("No bean specified");
1232 }
1233 if (name == null) {
1234 throw new IllegalArgumentException("No name specified for bean class '" +
1235 bean.getClass() + "'");
1236 }
1237
1238
1239 if (resolver.hasNested(name)) {
1240 throw new IllegalArgumentException
1241 ("Nested property names are not allowed: Property '" +
1242 name + "' on bean class '" + bean.getClass() + "'");
1243 } else if (resolver.isIndexed(name)) {
1244 throw new IllegalArgumentException
1245 ("Indexed property names are not allowed: Property '" +
1246 name + "' on bean class '" + bean.getClass() + "'");
1247 } else if (resolver.isMapped(name)) {
1248 throw new IllegalArgumentException
1249 ("Mapped property names are not allowed: Property '" +
1250 name + "' on bean class '" + bean.getClass() + "'");
1251 }
1252
1253
1254 if (bean instanceof DynaBean) {
1255 final DynaProperty descriptor =
1256 ((DynaBean) bean).getDynaClass().getDynaProperty(name);
1257 if (descriptor == null) {
1258 throw new NoSuchMethodException("Unknown property '" +
1259 name + "' on dynaclass '" +
1260 ((DynaBean) bean).getDynaClass() + "'" );
1261 }
1262 return (((DynaBean) bean).get(name));
1263 }
1264
1265
1266 final PropertyDescriptor descriptor =
1267 getPropertyDescriptor(bean, name);
1268 if (descriptor == null) {
1269 throw new NoSuchMethodException("Unknown property '" +
1270 name + "' on class '" + bean.getClass() + "'" );
1271 }
1272 final Method readMethod = getReadMethod(bean.getClass(), descriptor);
1273 if (readMethod == null) {
1274 throw new NoSuchMethodException("Property '" + name +
1275 "' has no getter method in class '" + bean.getClass() + "'");
1276 }
1277
1278
1279 final Object value = invokeMethod(readMethod, bean, EMPTY_OBJECT_ARRAY);
1280 return (value);
1281
1282 }
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299 public Method getWriteMethod(final PropertyDescriptor descriptor) {
1300
1301 return (MethodUtils.getAccessibleMethod(descriptor.getWriteMethod()));
1302
1303 }
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317 public Method getWriteMethod(final Class<?> clazz, final PropertyDescriptor descriptor) {
1318 final BeanIntrospectionData data = getIntrospectionData(clazz);
1319 return (MethodUtils.getAccessibleMethod(clazz,
1320 data.getWriteMethod(clazz, descriptor)));
1321 }
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339 public boolean isReadable(Object bean, String name) {
1340
1341
1342 if (bean == null) {
1343 throw new IllegalArgumentException("No bean specified");
1344 }
1345 if (name == null) {
1346 throw new IllegalArgumentException("No name specified for bean class '" +
1347 bean.getClass() + "'");
1348 }
1349
1350
1351 while (resolver.hasNested(name)) {
1352 final String next = resolver.next(name);
1353 Object nestedBean = null;
1354 try {
1355 nestedBean = getProperty(bean, next);
1356 } catch (final IllegalAccessException e) {
1357 return false;
1358 } catch (final InvocationTargetException e) {
1359 return false;
1360 } catch (final NoSuchMethodException e) {
1361 return false;
1362 }
1363 if (nestedBean == null) {
1364 throw new NestedNullException
1365 ("Null property value for '" + next +
1366 "' on bean class '" + bean.getClass() + "'");
1367 }
1368 bean = nestedBean;
1369 name = resolver.remove(name);
1370 }
1371
1372
1373 name = resolver.getProperty(name);
1374
1375
1376
1377 if (bean instanceof WrapDynaBean) {
1378 bean = ((WrapDynaBean)bean).getInstance();
1379 }
1380
1381
1382 if (bean instanceof DynaBean) {
1383
1384 return (((DynaBean) bean).getDynaClass().getDynaProperty(name) != null);
1385 } else {
1386 try {
1387 final PropertyDescriptor desc =
1388 getPropertyDescriptor(bean, name);
1389 if (desc != null) {
1390 Method readMethod = getReadMethod(bean.getClass(), desc);
1391 if (readMethod == null) {
1392 if (desc instanceof IndexedPropertyDescriptor) {
1393 readMethod = ((IndexedPropertyDescriptor) desc).getIndexedReadMethod();
1394 } else if (desc instanceof MappedPropertyDescriptor) {
1395 readMethod = ((MappedPropertyDescriptor) desc).getMappedReadMethod();
1396 }
1397 readMethod = MethodUtils.getAccessibleMethod(bean.getClass(), readMethod);
1398 }
1399 return (readMethod != null);
1400 } else {
1401 return (false);
1402 }
1403 } catch (final IllegalAccessException e) {
1404 return (false);
1405 } catch (final InvocationTargetException e) {
1406 return (false);
1407 } catch (final NoSuchMethodException e) {
1408 return (false);
1409 }
1410 }
1411
1412 }
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430 public boolean isWriteable(Object bean, String name) {
1431
1432
1433 if (bean == null) {
1434 throw new IllegalArgumentException("No bean specified");
1435 }
1436 if (name == null) {
1437 throw new IllegalArgumentException("No name specified for bean class '" +
1438 bean.getClass() + "'");
1439 }
1440
1441
1442 while (resolver.hasNested(name)) {
1443 final String next = resolver.next(name);
1444 Object nestedBean = null;
1445 try {
1446 nestedBean = getProperty(bean, next);
1447 } catch (final IllegalAccessException e) {
1448 return false;
1449 } catch (final InvocationTargetException e) {
1450 return false;
1451 } catch (final NoSuchMethodException e) {
1452 return false;
1453 }
1454 if (nestedBean == null) {
1455 throw new NestedNullException
1456 ("Null property value for '" + next +
1457 "' on bean class '" + bean.getClass() + "'");
1458 }
1459 bean = nestedBean;
1460 name = resolver.remove(name);
1461 }
1462
1463
1464 name = resolver.getProperty(name);
1465
1466
1467
1468 if (bean instanceof WrapDynaBean) {
1469 bean = ((WrapDynaBean)bean).getInstance();
1470 }
1471
1472
1473 if (bean instanceof DynaBean) {
1474
1475 return (((DynaBean) bean).getDynaClass().getDynaProperty(name) != null);
1476 } else {
1477 try {
1478 final PropertyDescriptor desc =
1479 getPropertyDescriptor(bean, name);
1480 if (desc != null) {
1481 Method writeMethod = getWriteMethod(bean.getClass(), desc);
1482 if (writeMethod == null) {
1483 if (desc instanceof IndexedPropertyDescriptor) {
1484 writeMethod = ((IndexedPropertyDescriptor) desc).getIndexedWriteMethod();
1485 } else if (desc instanceof MappedPropertyDescriptor) {
1486 writeMethod = ((MappedPropertyDescriptor) desc).getMappedWriteMethod();
1487 }
1488 writeMethod = MethodUtils.getAccessibleMethod(bean.getClass(), writeMethod);
1489 }
1490 return (writeMethod != null);
1491 } else {
1492 return (false);
1493 }
1494 } catch (final IllegalAccessException e) {
1495 return (false);
1496 } catch (final InvocationTargetException e) {
1497 return (false);
1498 } catch (final NoSuchMethodException e) {
1499 return (false);
1500 }
1501 }
1502
1503 }
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531 public void setIndexedProperty(final Object bean, String name,
1532 final Object value)
1533 throws IllegalAccessException, InvocationTargetException,
1534 NoSuchMethodException {
1535
1536 if (bean == null) {
1537 throw new IllegalArgumentException("No bean specified");
1538 }
1539 if (name == null) {
1540 throw new IllegalArgumentException("No name specified for bean class '" +
1541 bean.getClass() + "'");
1542 }
1543
1544
1545 int index = -1;
1546 try {
1547 index = resolver.getIndex(name);
1548 } catch (final IllegalArgumentException e) {
1549 throw new IllegalArgumentException("Invalid indexed property '" +
1550 name + "' on bean class '" + bean.getClass() + "'");
1551 }
1552 if (index < 0) {
1553 throw new IllegalArgumentException("Invalid indexed property '" +
1554 name + "' on bean class '" + bean.getClass() + "'");
1555 }
1556
1557
1558 name = resolver.getProperty(name);
1559
1560
1561 setIndexedProperty(bean, name, index, value);
1562
1563 }
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588 public void setIndexedProperty(final Object bean, final String name,
1589 final int index, final Object value)
1590 throws IllegalAccessException, InvocationTargetException,
1591 NoSuchMethodException {
1592
1593 if (bean == null) {
1594 throw new IllegalArgumentException("No bean specified");
1595 }
1596 if (name == null || name.length() == 0) {
1597 if (bean.getClass().isArray()) {
1598 Array.set(bean, index, value);
1599 return;
1600 } else if (bean instanceof List) {
1601 final List<Object> list = toObjectList(bean);
1602 list.set(index, value);
1603 return;
1604 }
1605 }
1606 if (name == null) {
1607 throw new IllegalArgumentException("No name specified for bean class '" +
1608 bean.getClass() + "'");
1609 }
1610
1611
1612 if (bean instanceof DynaBean) {
1613 final DynaProperty descriptor =
1614 ((DynaBean) bean).getDynaClass().getDynaProperty(name);
1615 if (descriptor == null) {
1616 throw new NoSuchMethodException("Unknown property '" +
1617 name + "' on bean class '" + bean.getClass() + "'");
1618 }
1619 ((DynaBean) bean).set(name, index, value);
1620 return;
1621 }
1622
1623
1624 final PropertyDescriptor descriptor =
1625 getPropertyDescriptor(bean, name);
1626 if (descriptor == null) {
1627 throw new NoSuchMethodException("Unknown property '" +
1628 name + "' on bean class '" + bean.getClass() + "'");
1629 }
1630
1631
1632 if (descriptor instanceof IndexedPropertyDescriptor) {
1633 Method writeMethod = ((IndexedPropertyDescriptor) descriptor).
1634 getIndexedWriteMethod();
1635 writeMethod = MethodUtils.getAccessibleMethod(bean.getClass(), writeMethod);
1636 if (writeMethod != null) {
1637 final Object[] subscript = new Object[2];
1638 subscript[0] = new Integer(index);
1639 subscript[1] = value;
1640 try {
1641 if (log.isTraceEnabled()) {
1642 final String valueClassName =
1643 value == null ? "<null>"
1644 : value.getClass().getName();
1645 log.trace("setSimpleProperty: Invoking method "
1646 + writeMethod +" with index=" + index
1647 + ", value=" + value
1648 + " (class " + valueClassName+ ")");
1649 }
1650 invokeMethod(writeMethod, bean, subscript);
1651 } catch (final InvocationTargetException e) {
1652 if (e.getTargetException() instanceof
1653 IndexOutOfBoundsException) {
1654 throw (IndexOutOfBoundsException)
1655 e.getTargetException();
1656 } else {
1657 throw e;
1658 }
1659 }
1660 return;
1661 }
1662 }
1663
1664
1665 final Method readMethod = getReadMethod(bean.getClass(), descriptor);
1666 if (readMethod == null) {
1667 throw new NoSuchMethodException("Property '" + name +
1668 "' has no getter method on bean class '" + bean.getClass() + "'");
1669 }
1670
1671
1672 final Object array = invokeMethod(readMethod, bean, EMPTY_OBJECT_ARRAY);
1673 if (!array.getClass().isArray()) {
1674 if (array instanceof List) {
1675
1676 final List<Object> list = toObjectList(array);
1677 list.set(index, value);
1678 } else {
1679 throw new IllegalArgumentException("Property '" + name +
1680 "' is not indexed on bean class '" + bean.getClass() + "'");
1681 }
1682 } else {
1683
1684 Array.set(array, index, value);
1685 }
1686
1687 }
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709 public void setMappedProperty(final Object bean, String name,
1710 final Object value)
1711 throws IllegalAccessException, InvocationTargetException,
1712 NoSuchMethodException {
1713
1714 if (bean == null) {
1715 throw new IllegalArgumentException("No bean specified");
1716 }
1717 if (name == null) {
1718 throw new IllegalArgumentException("No name specified for bean class '" +
1719 bean.getClass() + "'");
1720 }
1721
1722
1723 String key = null;
1724 try {
1725 key = resolver.getKey(name);
1726 } catch (final IllegalArgumentException e) {
1727 throw new IllegalArgumentException
1728 ("Invalid mapped property '" + name +
1729 "' on bean class '" + bean.getClass() + "'");
1730 }
1731 if (key == null) {
1732 throw new IllegalArgumentException
1733 ("Invalid mapped property '" + name +
1734 "' on bean class '" + bean.getClass() + "'");
1735 }
1736
1737
1738 name = resolver.getProperty(name);
1739
1740
1741 setMappedProperty(bean, name, key, value);
1742
1743 }
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762 public void setMappedProperty(final Object bean, final String name,
1763 final String key, final Object value)
1764 throws IllegalAccessException, InvocationTargetException,
1765 NoSuchMethodException {
1766
1767 if (bean == null) {
1768 throw new IllegalArgumentException("No bean specified");
1769 }
1770 if (name == null) {
1771 throw new IllegalArgumentException("No name specified for bean class '" +
1772 bean.getClass() + "'");
1773 }
1774 if (key == null) {
1775 throw new IllegalArgumentException("No key specified for property '" +
1776 name + "' on bean class '" + bean.getClass() + "'");
1777 }
1778
1779
1780 if (bean instanceof DynaBean) {
1781 final DynaProperty descriptor =
1782 ((DynaBean) bean).getDynaClass().getDynaProperty(name);
1783 if (descriptor == null) {
1784 throw new NoSuchMethodException("Unknown property '" +
1785 name + "' on bean class '" + bean.getClass() + "'");
1786 }
1787 ((DynaBean) bean).set(name, key, value);
1788 return;
1789 }
1790
1791
1792 final PropertyDescriptor descriptor =
1793 getPropertyDescriptor(bean, name);
1794 if (descriptor == null) {
1795 throw new NoSuchMethodException("Unknown property '" +
1796 name + "' on bean class '" + bean.getClass() + "'");
1797 }
1798
1799 if (descriptor instanceof MappedPropertyDescriptor) {
1800
1801 Method mappedWriteMethod =
1802 ((MappedPropertyDescriptor) descriptor).
1803 getMappedWriteMethod();
1804 mappedWriteMethod = MethodUtils.getAccessibleMethod(bean.getClass(), mappedWriteMethod);
1805 if (mappedWriteMethod != null) {
1806 final Object[] params = new Object[2];
1807 params[0] = key;
1808 params[1] = value;
1809 if (log.isTraceEnabled()) {
1810 final String valueClassName =
1811 value == null ? "<null>" : value.getClass().getName();
1812 log.trace("setSimpleProperty: Invoking method "
1813 + mappedWriteMethod + " with key=" + key
1814 + ", value=" + value
1815 + " (class " + valueClassName +")");
1816 }
1817 invokeMethod(mappedWriteMethod, bean, params);
1818 } else {
1819 throw new NoSuchMethodException
1820 ("Property '" + name + "' has no mapped setter method" +
1821 "on bean class '" + bean.getClass() + "'");
1822 }
1823 } else {
1824
1825 final Method readMethod = getReadMethod(bean.getClass(), descriptor);
1826 if (readMethod != null) {
1827 final Object invokeResult = invokeMethod(readMethod, bean, EMPTY_OBJECT_ARRAY);
1828
1829 if (invokeResult instanceof java.util.Map) {
1830 final java.util.Map<String, Object> map = toPropertyMap(invokeResult);
1831 map.put(key, value);
1832 }
1833 } else {
1834 throw new NoSuchMethodException("Property '" + name +
1835 "' has no mapped getter method on bean class '" +
1836 bean.getClass() + "'");
1837 }
1838 }
1839
1840 }
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873 public void setNestedProperty(Object bean,
1874 String name, final Object value)
1875 throws IllegalAccessException, InvocationTargetException,
1876 NoSuchMethodException {
1877
1878 if (bean == null) {
1879 throw new IllegalArgumentException("No bean specified");
1880 }
1881 if (name == null) {
1882 throw new IllegalArgumentException("No name specified for bean class '" +
1883 bean.getClass() + "'");
1884 }
1885
1886
1887 while (resolver.hasNested(name)) {
1888 final String next = resolver.next(name);
1889 Object nestedBean = null;
1890 if (bean instanceof Map) {
1891 nestedBean = getPropertyOfMapBean((Map<?, ?>)bean, next);
1892 } else if (resolver.isMapped(next)) {
1893 nestedBean = getMappedProperty(bean, next);
1894 } else if (resolver.isIndexed(next)) {
1895 nestedBean = getIndexedProperty(bean, next);
1896 } else {
1897 nestedBean = getSimpleProperty(bean, next);
1898 }
1899 if (nestedBean == null) {
1900 throw new NestedNullException
1901 ("Null property value for '" + name +
1902 "' on bean class '" + bean.getClass() + "'");
1903 }
1904 bean = nestedBean;
1905 name = resolver.remove(name);
1906 }
1907
1908 if (bean instanceof Map) {
1909 setPropertyOfMapBean(toPropertyMap(bean), name, value);
1910 } else if (resolver.isMapped(name)) {
1911 setMappedProperty(bean, name, value);
1912 } else if (resolver.isIndexed(name)) {
1913 setIndexedProperty(bean, name, value);
1914 } else {
1915 setSimpleProperty(bean, name, value);
1916 }
1917
1918 }
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976 protected void setPropertyOfMapBean(final Map<String, Object> bean, String propertyName, final Object value)
1977 throws IllegalArgumentException, IllegalAccessException,
1978 InvocationTargetException, NoSuchMethodException {
1979
1980 if (resolver.isMapped(propertyName)) {
1981 final String name = resolver.getProperty(propertyName);
1982 if (name == null || name.length() == 0) {
1983 propertyName = resolver.getKey(propertyName);
1984 }
1985 }
1986
1987 if (resolver.isIndexed(propertyName) ||
1988 resolver.isMapped(propertyName)) {
1989 throw new IllegalArgumentException(
1990 "Indexed or mapped properties are not supported on"
1991 + " objects of type Map: " + propertyName);
1992 }
1993
1994 bean.put(propertyName, value);
1995 }
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018 public void setProperty(final Object bean, final String name, final Object value)
2019 throws IllegalAccessException, InvocationTargetException,
2020 NoSuchMethodException {
2021
2022 setNestedProperty(bean, name, value);
2023
2024 }
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046 public void setSimpleProperty(final Object bean,
2047 final String name, final Object value)
2048 throws IllegalAccessException, InvocationTargetException,
2049 NoSuchMethodException {
2050
2051 if (bean == null) {
2052 throw new IllegalArgumentException("No bean specified");
2053 }
2054 if (name == null) {
2055 throw new IllegalArgumentException("No name specified for bean class '" +
2056 bean.getClass() + "'");
2057 }
2058
2059
2060 if (resolver.hasNested(name)) {
2061 throw new IllegalArgumentException
2062 ("Nested property names are not allowed: Property '" +
2063 name + "' on bean class '" + bean.getClass() + "'");
2064 } else if (resolver.isIndexed(name)) {
2065 throw new IllegalArgumentException
2066 ("Indexed property names are not allowed: Property '" +
2067 name + "' on bean class '" + bean.getClass() + "'");
2068 } else if (resolver.isMapped(name)) {
2069 throw new IllegalArgumentException
2070 ("Mapped property names are not allowed: Property '" +
2071 name + "' on bean class '" + bean.getClass() + "'");
2072 }
2073
2074
2075 if (bean instanceof DynaBean) {
2076 final DynaProperty descriptor =
2077 ((DynaBean) bean).getDynaClass().getDynaProperty(name);
2078 if (descriptor == null) {
2079 throw new NoSuchMethodException("Unknown property '" +
2080 name + "' on dynaclass '" +
2081 ((DynaBean) bean).getDynaClass() + "'" );
2082 }
2083 ((DynaBean) bean).set(name, value);
2084 return;
2085 }
2086
2087
2088 final PropertyDescriptor descriptor =
2089 getPropertyDescriptor(bean, name);
2090 if (descriptor == null) {
2091 throw new NoSuchMethodException("Unknown property '" +
2092 name + "' on class '" + bean.getClass() + "'" );
2093 }
2094 final Method writeMethod = getWriteMethod(bean.getClass(), descriptor);
2095 if (writeMethod == null) {
2096 throw new NoSuchMethodException("Property '" + name +
2097 "' has no setter method in class '" + bean.getClass() + "'");
2098 }
2099
2100
2101 final Object[] values = new Object[1];
2102 values[0] = value;
2103 if (log.isTraceEnabled()) {
2104 final String valueClassName =
2105 value == null ? "<null>" : value.getClass().getName();
2106 log.trace("setSimpleProperty: Invoking method " + writeMethod
2107 + " with value " + value + " (class " + valueClassName + ")");
2108 }
2109 invokeMethod(writeMethod, bean, values);
2110
2111 }
2112
2113
2114 private Object invokeMethod(
2115 final Method method,
2116 final Object bean,
2117 final Object[] values)
2118 throws
2119 IllegalAccessException,
2120 InvocationTargetException {
2121 if(bean == null) {
2122 throw new IllegalArgumentException("No bean specified " +
2123 "- this should have been checked before reaching this method");
2124 }
2125
2126 try {
2127
2128 return method.invoke(bean, values);
2129
2130 } catch (final NullPointerException cause) {
2131
2132
2133 String valueString = "";
2134 if (values != null) {
2135 for (int i = 0; i < values.length; i++) {
2136 if (i>0) {
2137 valueString += ", " ;
2138 }
2139 if (values[i] == null) {
2140 valueString += "<null>";
2141 } else {
2142 valueString += (values[i]).getClass().getName();
2143 }
2144 }
2145 }
2146 String expectedString = "";
2147 final Class<?>[] parTypes = method.getParameterTypes();
2148 if (parTypes != null) {
2149 for (int i = 0; i < parTypes.length; i++) {
2150 if (i > 0) {
2151 expectedString += ", ";
2152 }
2153 expectedString += parTypes[i].getName();
2154 }
2155 }
2156 final IllegalArgumentException e = new IllegalArgumentException(
2157 "Cannot invoke " + method.getDeclaringClass().getName() + "."
2158 + method.getName() + " on bean class '" + bean.getClass() +
2159 "' - " + cause.getMessage()
2160
2161 + " - had objects of type \"" + valueString
2162 + "\" but expected signature \""
2163 + expectedString + "\""
2164 );
2165 if (!BeanUtils.initCause(e, cause)) {
2166 log.error("Method invocation failed", cause);
2167 }
2168 throw e;
2169 } catch (final IllegalArgumentException cause) {
2170 String valueString = "";
2171 if (values != null) {
2172 for (int i = 0; i < values.length; i++) {
2173 if (i>0) {
2174 valueString += ", " ;
2175 }
2176 if (values[i] == null) {
2177 valueString += "<null>";
2178 } else {
2179 valueString += (values[i]).getClass().getName();
2180 }
2181 }
2182 }
2183 String expectedString = "";
2184 final Class<?>[] parTypes = method.getParameterTypes();
2185 if (parTypes != null) {
2186 for (int i = 0; i < parTypes.length; i++) {
2187 if (i > 0) {
2188 expectedString += ", ";
2189 }
2190 expectedString += parTypes[i].getName();
2191 }
2192 }
2193 final IllegalArgumentException e = new IllegalArgumentException(
2194 "Cannot invoke " + method.getDeclaringClass().getName() + "."
2195 + method.getName() + " on bean class '" + bean.getClass() +
2196 "' - " + cause.getMessage()
2197
2198 + " - had objects of type \"" + valueString
2199 + "\" but expected signature \""
2200 + expectedString + "\""
2201 );
2202 if (!BeanUtils.initCause(e, cause)) {
2203 log.error("Method invocation failed", cause);
2204 }
2205 throw e;
2206
2207 }
2208 }
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219 private BeanIntrospectionData getIntrospectionData(final Class<?> beanClass) {
2220 if (beanClass == null) {
2221 throw new IllegalArgumentException("No bean class specified");
2222 }
2223
2224
2225 BeanIntrospectionData data = descriptorsCache.get(beanClass);
2226 if (data == null) {
2227 data = fetchIntrospectionData(beanClass);
2228 descriptorsCache.put(beanClass, data);
2229 }
2230
2231 return data;
2232 }
2233
2234
2235
2236
2237
2238
2239
2240
2241 private BeanIntrospectionData fetchIntrospectionData(final Class<?> beanClass) {
2242 final DefaultIntrospectionContext ictx = new DefaultIntrospectionContext(beanClass);
2243
2244 for (final BeanIntrospector bi : introspectors) {
2245 try {
2246 bi.introspect(ictx);
2247 } catch (final IntrospectionException iex) {
2248 log.error("Exception during introspection", iex);
2249 }
2250 }
2251
2252 return new BeanIntrospectionData(ictx.getPropertyDescriptors());
2253 }
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263 private static List<Object> toObjectList(final Object obj) {
2264 @SuppressWarnings("unchecked")
2265 final
2266
2267 List<Object> list = (List<Object>) obj;
2268 return list;
2269 }
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279 private static Map<String, Object> toPropertyMap(final Object obj) {
2280 @SuppressWarnings("unchecked")
2281 final
2282
2283 Map<String, Object> map = (Map<String, Object>) obj;
2284 return map;
2285 }
2286 }