KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jodd > bean > BeanUtil


1 // Copyright (c) 2003-2007, Jodd Team (jodd.sf.net). All Rights Reserved.
2

3 package jodd.bean;
4
5 import java.lang.reflect.Method JavaDoc;
6 import java.lang.reflect.Array JavaDoc;
7 import java.lang.reflect.Field JavaDoc;
8 import java.util.Map JavaDoc;
9 import java.util.List JavaDoc;
10
11 /**
12  * Yet another utility for reading and writing bean properties. However, this one is the fastest availiable.
13  * Althought it provides various methods, the whole thing can be easily extended to match most needs.
14  * <p>
15  * BeanUtil supports:
16  * <ul>
17  * <li>Nested properties: separated by a dot ('.')</li>
18  * <li>Indexed properties: arrays or Lists</li>
19  * <li>Simple properties: accessors or Map</li>
20  * </ul>
21  *
22  * <p>
23  * Variants includes combinations of forced, declared and silent writing.
24  * <ul>
25  * <li><i>Forced</i> setting property tries to create destination property so it can be set correctly.</li>
26  * <li><i>Silent</i> doesn't throw an exception if destination doesn't exist or if conversion fails.</li>
27  * <li><i>Declared</i> includes only declared (public) properties.</li>
28  * </ul>
29  * <p>
30  * This utility considers both bean property methods (set and get accessors), and bean fields.
31  * This is done because of several reasons: often there is no need for both set/get accessors, since
32  * bean logic requires just one functionality (e.g. just reading). In such case, other bean manipulation
33  * libraries still requires to have both accessors in order to set or get value.
34  * Another reason is that most common usage is to work with public accessort, and in that case
35  * private fields are ignored.
36  *
37  * @see BeanPropertyUtil
38  */

39 public class BeanUtil {
40
41     // ---------------------------------------------------------------- internal resolver
42

43     /**
44      * Resolves nested property name to the very last indexed property.
45      * If forced, <code>null</code> or non-existing properties will be created.
46      */

47     protected static void resolveNestedProperties(BeanProperty beanProperty, boolean forced) {
48         String JavaDoc name = beanProperty.name;
49         int dotNdx;
50         while ((dotNdx = name.indexOf('.')) != -1) {
51             beanProperty.last = false;
52             beanProperty.name = name.substring(0, dotNdx);
53             beanProperty.setBean(getIndexProperty(beanProperty, true, forced));
54             name = name.substring(dotNdx + 1);
55         }
56         beanProperty.last = true;
57         beanProperty.name = name;
58     }
59
60     protected static boolean resolveExistingNestedProperties(BeanProperty beanProperty) {
61         String JavaDoc name = beanProperty.name;
62         int dotNdx;
63         while ((dotNdx = name.indexOf('.')) != -1) {
64             beanProperty.last = false;
65             String JavaDoc temp = beanProperty.name = name.substring(0, dotNdx);
66             if (hasIndexProperty(beanProperty, true) == false) {
67                 return false;
68             }
69             beanProperty.name = temp;
70             beanProperty.setBean(getIndexProperty(beanProperty, true, false));
71             name = name.substring(dotNdx + 1);
72         }
73         beanProperty.last = true;
74         beanProperty.name = name;
75         return true;
76     }
77
78
79     // ---------------------------------------------------------------- simple property
80

81     /**
82      * Returns <code>true</code> if simple property exist.
83      */

84     public static boolean hasSimpleProperty(Object JavaDoc bean, String JavaDoc property, boolean suppressSecurity) {
85         return hasSimpleProperty(new BeanProperty(bean, property), suppressSecurity);
86     }
87     public static boolean hasSimpleProperty(BeanProperty bp, boolean suppressSecurity) {
88         if (bp.bean == null) {
89             return false;
90         }
91
92         // try: getProperty() or isProperty()
93
Method JavaDoc method = bp.cd.getBeanGetter(bp.name, suppressSecurity);
94         if (method != null) {
95             return true;
96         }
97
98         // try: =property
99
Field JavaDoc field = bp.cd.getField(bp.name, suppressSecurity);
100         if (field != null) {
101             return true;
102         }
103
104         // try: (Map) get("property")
105
if (bp.cd.isMap()) {
106             Map JavaDoc map = (Map JavaDoc) bp.bean;
107             if (map.containsKey(bp.name) == true) {
108                 return true;
109             }
110         }
111
112         return false;
113     }
114
115
116
117     /**
118      * Reads simple property.
119      */

120     public static Object JavaDoc getSimpleProperty(Object JavaDoc bean, String JavaDoc property, boolean suppressSecurity) {
121         return getSimpleProperty(new BeanProperty(bean, property), suppressSecurity);
122     }
123
124     protected static Object JavaDoc getSimpleProperty(BeanProperty bp, boolean suppressSecurity) {
125
126         // try: getProperty() or isProperty()
127
Method JavaDoc method = bp.cd.getBeanGetter(bp.name, suppressSecurity);
128         if (method != null) {
129             return BeanPropertyUtil.invokeGetter(bp.bean, method);
130         }
131
132         // try: =property
133
Field JavaDoc field = bp.cd.getField(bp.name, suppressSecurity);
134         if (field != null) {
135             return BeanPropertyUtil.getField(bp.bean, field);
136         }
137
138         // try: (Map) get("property")
139
if (bp.cd.isMap()) {
140             Map JavaDoc map = (Map JavaDoc) bp.bean;
141             if (map.containsKey(bp.name) == false) {
142                 throw new BeanException("Unable to read simple map property '" + bp + '\'');
143             }
144             return map.get(bp.name);
145         }
146         
147         // failed
148
throw new BeanException("Unable to read simple property '" + bp + '\'');
149     }
150
151     /**
152      * Reads simple property forced, so if it doesn't exist, it will be created.
153      */

154     public static Object JavaDoc getSimplePropertyForced(Object JavaDoc bean, String JavaDoc property, boolean suppressSecurity) {
155         return getSimplePropertyForced(new BeanProperty(bean, property), suppressSecurity);
156     }
157
158     protected static Object JavaDoc getSimplePropertyForced(BeanProperty bp, boolean suppressSecurity) {
159
160         // try: getProperty() or isProperty()
161
Method JavaDoc method = bp.cd.getBeanGetter(bp.name, suppressSecurity);
162         if (method != null) {
163             Object JavaDoc result = BeanPropertyUtil.invokeGetter(bp.bean, method);
164             if (result == null) {
165                 result = BeanPropertyUtil.createBeanProperty(bp);
166             }
167             return result;
168         }
169         // try: property=
170
Field JavaDoc field = bp.cd.getField(bp.name, suppressSecurity);
171         if (field != null) {
172             Object JavaDoc result = BeanPropertyUtil.getField(bp.bean, field);
173             if (result == null) {
174                 result = BeanPropertyUtil.createBeanProperty(bp);
175             }
176             return result;
177         }
178
179         // try: (Map) get("property")
180
if (bp.cd.isMap()) {
181             Map JavaDoc map = (Map JavaDoc) bp.bean;
182             if (map.containsKey(bp.name) == false) {
183                 return BeanPropertyUtil.createMapProperty(map, bp.name);
184             }
185             return map.get(bp.name);
186         }
187         
188         // failed
189
throw new BeanException("Unable to read forced simple property '" + bp + '\'');
190     }
191
192
193     public static void setSimpleProperty(Object JavaDoc bean, String JavaDoc property, Object JavaDoc value, boolean suppressSecurity) {
194         setSimpleProperty(new BeanProperty(bean, property), value, suppressSecurity);
195     }
196
197     public static boolean setSimplePropertySilent(Object JavaDoc bean, String JavaDoc property, Object JavaDoc value, boolean suppressSecurity) {
198         return setSimplePropertySilent(new BeanProperty(bean, property), value, suppressSecurity);
199     }
200
201     /**
202      * Sets a value of simple property.
203      */

204     protected static boolean setSimplePropertySilent(BeanProperty bp, Object JavaDoc value, boolean suppressSecurity) {
205
206         // try: setProperty(value)
207
Method JavaDoc method = bp.cd.getBeanSetter(bp.name, suppressSecurity);
208         if (method != null) {
209             return BeanPropertyUtil.invokeSetterSilent(bp.bean, method, value);
210         }
211
212         // try: property=
213
Field JavaDoc field = bp.cd.getField(bp.name, suppressSecurity);
214         if (field != null) {
215             return BeanPropertyUtil.setFieldSilent(bp.bean, field, value);
216         }
217
218         // try: put("property", value)
219
if (bp.cd.isMap() == true) {
220             ((Map JavaDoc) bp.bean).put(bp.name, value);
221             return true;
222         }
223
224         return false;
225     }
226
227     /**
228      * Sets a value of simple property.
229      */

230     protected static void setSimpleProperty(BeanProperty bp, Object JavaDoc value, boolean suppressSecurity) {
231
232         // try: setProperty(value)
233
Method JavaDoc method = bp.cd.getBeanSetter(bp.name, suppressSecurity);
234         if (method != null) {
235             BeanPropertyUtil.invokeSetter(bp.bean, method, value);
236             return;
237         }
238
239         // try: property=
240
Field JavaDoc field = bp.cd.getField(bp.name, suppressSecurity);
241         if (field != null) {
242             BeanPropertyUtil.setField(bp.bean, field, value);
243             return;
244         }
245
246         // try: put("property", value)
247
if (bp.cd.isMap() == true) {
248             ((Map JavaDoc) bp.bean).put(bp.name, value);
249             return;
250         }
251
252         throw new BeanException("Unable to set property '" + bp + '\'');
253     }
254
255
256
257
258     // ---------------------------------------------------------------- indexed property
259

260     public static boolean hasIndexProperty(Object JavaDoc bean, String JavaDoc property, boolean suppressSecurity) {
261         return hasIndexProperty(new BeanProperty(bean, property), suppressSecurity);
262     }
263
264     protected static boolean hasIndexProperty(BeanProperty bp, boolean suppressSecurity) {
265         
266         if (bp.bean == null) {
267             return false;
268         }
269         String JavaDoc indexString = BeanPropertyUtil.extractIndex(bp);
270
271         if (indexString == null) {
272             return hasSimpleProperty(bp, suppressSecurity);
273         }
274         
275         Object JavaDoc resultBean = getSimpleProperty(bp, suppressSecurity);
276
277         if (resultBean == null) {
278             return false;
279         }
280
281         // try: property[index]
282
if (resultBean.getClass().isArray() == true) {
283             int index = 0;
284             try {
285                 index = Integer.parseInt(indexString);
286             } catch (NumberFormatException JavaDoc nfex) {
287                 throw new BeanException("Provided index '" + index + "' is not a number.", nfex);
288             }
289             return (index >= 0) && (index < Array.getLength(resultBean));
290         }
291
292         // try: list.get(index)
293
if (resultBean instanceof List JavaDoc) {
294             int index = 0;
295             try {
296                 index = Integer.parseInt(indexString);
297             } catch (NumberFormatException JavaDoc nfex) {
298                 throw new BeanException("Provided index '" + index + "' is not a number.", nfex);
299             }
300             return (index >= 0) && (index < ((List JavaDoc)resultBean).size());
301         }
302         if (resultBean instanceof Map JavaDoc) {
303             return ((Map JavaDoc)resultBean).containsKey(indexString);
304         }
305
306         // failed
307
return false;
308     }
309
310
311     public static Object JavaDoc getIndexProperty(Object JavaDoc bean, String JavaDoc property, boolean suppressSecurity, boolean forced) {
312         return getIndexProperty(new BeanProperty(bean, property), suppressSecurity, forced);
313     }
314
315     /**
316      * Get non-nested property value: either simple or indexed property.
317      * If forced, missing bean will be created if possible.
318      */

319     protected static Object JavaDoc getIndexProperty(BeanProperty bp, boolean suppressSecurity, boolean forced) {
320         String JavaDoc indexString = BeanPropertyUtil.extractIndex(bp);
321
322         Object JavaDoc resultBean =
323                 forced == true ?
324                 getSimplePropertyForced(bp, suppressSecurity) :
325                 getSimpleProperty(bp, suppressSecurity);
326
327         if (indexString == null) {
328             return resultBean; // no index, just simple bean
329
}
330
331         if (resultBean == null) {
332             throw new BeanException("Value of index property '" + bp + "' is null.");
333         }
334
335         // try: property[index]
336
if (resultBean.getClass().isArray() == true) {
337             int index = 0;
338             try {
339                 index = Integer.parseInt(indexString);
340             } catch (NumberFormatException JavaDoc nfex) {
341                 throw new BeanException("Provided index '" + index + "' is not a number.", nfex);
342             }
343             if (forced == true) {
344                 return BeanPropertyUtil.arrayForcedGet(bp, resultBean, index);
345             } else {
346                 return Array.get(resultBean, index);
347             }
348         }
349
350         // try: list.get(index)
351
if (resultBean instanceof List JavaDoc) {
352             int index = 0;
353             try {
354                 index = Integer.parseInt(indexString);
355             } catch (NumberFormatException JavaDoc nfex) {
356                 throw new BeanException("Provided index '" + index + "' is not a number.", nfex);
357             }
358             if (forced == true) {
359                 return BeanPropertyUtil.listForcedGet(bp, (List JavaDoc)resultBean, index);
360             } else {
361                 return ((List JavaDoc)resultBean).get(index);
362             }
363         }
364         if (resultBean instanceof Map JavaDoc) {
365             if (forced == true) {
366                 return BeanPropertyUtil.mapForcedGet(bp, (Map JavaDoc)resultBean, indexString);
367             } else {
368                 return ((Map JavaDoc)resultBean).get(indexString);
369             }
370         }
371
372         // failed
373
throw new BeanException("Unable to read inner indexed property '" + bp + '\'');
374     }
375
376
377
378     public static void setIndexProperty(Object JavaDoc bean, String JavaDoc property, Object JavaDoc value, boolean suppressSecurity, boolean forced) {
379         setIndexProperty(new BeanProperty(bean, property), value, suppressSecurity, forced, false);
380     }
381
382     public static boolean setIndexPropertySilent(Object JavaDoc bean, String JavaDoc property, Object JavaDoc value, boolean suppressSecurity, boolean forced) {
383         return setIndexProperty(new BeanProperty(bean, property), value, suppressSecurity, forced, true);
384     }
385
386     /**
387      * Sets indexed or regular properties (no nested!).
388      */

389     protected static boolean setIndexProperty(BeanProperty beanProperty, Object JavaDoc value, boolean suppressSecurity, boolean forced, boolean silent) {
390         String JavaDoc indexString = BeanPropertyUtil.extractIndex(beanProperty);
391
392         if (indexString == null) {
393             if (silent == true) {
394                 return setSimplePropertySilent(beanProperty, value, suppressSecurity);
395             }
396             setSimpleProperty(beanProperty, value, suppressSecurity);
397             return true;
398         }
399
400         // try: getInner()
401
Object JavaDoc nextBean =
402                 forced == true ?
403                 getSimplePropertyForced(beanProperty, suppressSecurity) :
404                 getSimpleProperty(beanProperty, suppressSecurity);
405
406         // inner bean found
407
if (nextBean.getClass().isArray() == true) {
408             int index = 0;
409             try {
410                 index = Integer.parseInt(indexString);
411             } catch (NumberFormatException JavaDoc nfex) {
412                 throw new BeanException("Provided index '" + index + "' is not a number.", nfex);
413             }
414             if (forced == true) {
415                 BeanPropertyUtil.arrayForcedSet(beanProperty, nextBean, index, value);
416             } else {
417                 Array.set(nextBean, index, value);
418             }
419             return true;
420         }
421
422         if (nextBean instanceof List JavaDoc) {
423             int index = 0;
424             try {
425                 index = Integer.parseInt(indexString);
426             } catch (NumberFormatException JavaDoc nfex) {
427                 throw new BeanException("Provided index '" + index + "' is not a number.", nfex);
428             }
429             if (forced == true) {
430                 BeanPropertyUtil.listForcedSet((List JavaDoc) nextBean, index, value);
431             } else {
432                 ((List JavaDoc) nextBean).add(index, value);
433             }
434             return true;
435         }
436         if (nextBean instanceof Map JavaDoc) {
437             ((Map JavaDoc) nextBean).put(indexString, value);
438             return true;
439         }
440         if (silent == true) {
441             return false;
442         }
443         throw new BeanException("Unable to set index property '" + beanProperty + '\'');
444     }
445
446
447     // ---------------------------------------------------------------- SET
448

449     /**
450      * Sets Java Bean property.
451      */

452     public static void setProperty(Object JavaDoc bean, String JavaDoc name, Object JavaDoc value) {
453         BeanProperty beanProperty = new BeanProperty(bean, name);
454         resolveNestedProperties(beanProperty, false);
455         setIndexProperty(beanProperty, value, false, false, false);
456     }
457     /**
458      * Sets Java Bean property silently, without throwing an exception on non-existing properties.
459      */

460     public static boolean setPropertySilent(Object JavaDoc bean, String JavaDoc name, Object JavaDoc value) {
461         BeanProperty beanProperty = new BeanProperty(bean, name);
462         resolveNestedProperties(beanProperty, false);
463         return setIndexProperty(beanProperty, value, false, false, true);
464     }
465
466     /**
467      * Sets Java Bean property forced.
468      */

469     public static void setPropertyForced(Object JavaDoc bean, String JavaDoc name, Object JavaDoc value) {
470         BeanProperty beanProperty = new BeanProperty(bean, name);
471         resolveNestedProperties(beanProperty, true);
472         setIndexProperty(beanProperty, value, false, true, false);
473     }
474     public static boolean setPropertyForcedSilent(Object JavaDoc bean, String JavaDoc name, Object JavaDoc value) {
475         BeanProperty beanProperty = new BeanProperty(bean, name);
476         resolveNestedProperties(beanProperty, true);
477         return setIndexProperty(beanProperty, value, false, true, true);
478     }
479
480     /**
481      * Sets declared Java Bean property.
482      */

483     public static void setDeclaredProperty(Object JavaDoc bean, String JavaDoc name, Object JavaDoc value) {
484         BeanProperty beanProperty = new BeanProperty(bean, name);
485         resolveNestedProperties(beanProperty, false);
486         setIndexProperty(beanProperty, value, true, false, false);
487     }
488     public static boolean setDeclaredPropertySilent(Object JavaDoc bean, String JavaDoc name, Object JavaDoc value) {
489         BeanProperty beanProperty = new BeanProperty(bean, name);
490         resolveNestedProperties(beanProperty, false);
491         return setIndexProperty(beanProperty, value, true, false, true);
492     }
493     /**
494      * Sets declared Java Bean property forced.
495      */

496     public static void setDeclaredPropertyForced(Object JavaDoc bean, String JavaDoc name, Object JavaDoc value) {
497         BeanProperty beanProperty = new BeanProperty(bean, name);
498         resolveNestedProperties(beanProperty, true);
499         setIndexProperty(beanProperty, value, true, true, false);
500     }
501     public static boolean setDeclaredPropertyForcedSilent(Object JavaDoc bean, String JavaDoc name, Object JavaDoc value) {
502         BeanProperty beanProperty = new BeanProperty(bean, name);
503         resolveNestedProperties(beanProperty, true);
504         return setIndexProperty(beanProperty, value, true, true, true);
505     }
506
507
508     // ---------------------------------------------------------------- GET
509

510     /**
511      * Returns value of bean's property.
512      */

513     public static Object JavaDoc getProperty(Object JavaDoc bean, String JavaDoc name) {
514         BeanProperty beanProperty = new BeanProperty(bean, name);
515         resolveNestedProperties(beanProperty, false);
516         return getIndexProperty(beanProperty, false, false);
517     }
518     /**
519      * Returns value of declared bean's property.
520      */

521     public static Object JavaDoc getDeclaredProperty(Object JavaDoc bean, String JavaDoc name) {
522         BeanProperty beanProperty = new BeanProperty(bean, name);
523         resolveNestedProperties(beanProperty, false);
524         return getIndexProperty(beanProperty, true, false);
525     }
526
527
528     // ---------------------------------------------------------------- HAS
529

530     public static boolean hasProperty(Object JavaDoc bean, String JavaDoc name) {
531         BeanProperty beanProperty = new BeanProperty(bean, name);
532         if (resolveExistingNestedProperties(beanProperty) == false) {
533             return false;
534         }
535         return hasIndexProperty(beanProperty, false);
536     }
537
538     public static boolean hasDeclaredProperty(Object JavaDoc bean, String JavaDoc name) {
539         BeanProperty beanProperty = new BeanProperty(bean, name);
540         if (resolveExistingNestedProperties(beanProperty) == false) {
541             return false;
542         }
543         return hasIndexProperty(beanProperty, true);
544     }
545
546 }
547
Popular Tags