1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.nuiton.util.beans;
23
24 import com.google.common.base.Predicate;
25 import com.google.common.base.Predicates;
26 import org.apache.commons.beanutils.MethodUtils;
27 import org.apache.commons.beanutils.PropertyUtils;
28
29 import java.beans.PropertyChangeListener;
30 import java.beans.PropertyDescriptor;
31 import java.lang.reflect.InvocationTargetException;
32 import java.lang.reflect.Method;
33 import java.util.HashSet;
34 import java.util.Map;
35 import java.util.Set;
36 import java.util.TreeMap;
37
38
39
40
41
42
43
44 public class BeanUtil {
45
46 public static final String ADD_PROPERTY_CHANGE_LISTENER =
47 "addPropertyChangeListener";
48
49 public static final String REMOVE_PROPERTY_CHANGE_LISTENER =
50 "removePropertyChangeListener";
51
52 protected BeanUtil() {
53
54 }
55
56
57
58
59
60
61 public static final Predicate<PropertyDescriptor> IS_READ_DESCRIPTOR = new Predicate<PropertyDescriptor>() {
62 @Override
63 public boolean apply(PropertyDescriptor input) {
64 return input.getReadMethod() != null;
65 }
66
67 @Override
68 public boolean test(PropertyDescriptor input) {
69 return apply(input);
70 }
71 };
72
73
74
75
76
77
78 public static final Predicate<PropertyDescriptor> IS_WRITE_DESCRIPTOR = new Predicate<PropertyDescriptor>() {
79 @Override
80 public boolean apply(PropertyDescriptor input) {
81 return input.getWriteMethod() != null;
82 }
83
84 @Override
85 public boolean test(PropertyDescriptor input) {
86 return apply(input);
87 }
88 };
89
90
91
92
93
94
95 public static final Predicate<PropertyDescriptor> IS_READ_AND_WRITE_DESCRIPTOR = Predicates.and(
96 IS_READ_DESCRIPTOR,
97 IS_WRITE_DESCRIPTOR
98 );
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113 public static boolean isJavaBeanCompiliant(Class<?> type) {
114
115 try {
116 type.getMethod(ADD_PROPERTY_CHANGE_LISTENER,
117 PropertyChangeListener.class);
118 } catch (NoSuchMethodException e) {
119
120 return false;
121 }
122
123 try {
124 type.getMethod(REMOVE_PROPERTY_CHANGE_LISTENER,
125 PropertyChangeListener.class);
126 } catch (NoSuchMethodException e) {
127
128 return false;
129 }
130
131 return true;
132 }
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149 public static void addPropertyChangeListener(PropertyChangeListener listener,
150 Object bean) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
151 MethodUtils.invokeExactMethod(bean,
152 ADD_PROPERTY_CHANGE_LISTENER,
153 new Object[]{listener},
154 new Class[]{PropertyChangeListener.class}
155 );
156 }
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173 public static void removePropertyChangeListener(PropertyChangeListener listener,
174 Object bean) throws InvocationTargetException, NoSuchMethodException, IllegalAccessException {
175 MethodUtils.invokeExactMethod(bean,
176 REMOVE_PROPERTY_CHANGE_LISTENER,
177 new Object[]{listener},
178 new Class[]{PropertyChangeListener.class}
179 );
180 }
181
182
183
184
185
186
187
188
189 public static Set<String> getReadableProperties(Class<?> beanType) {
190 Set<Class<?>> exploredTypes = new HashSet<Class<?>>();
191 Set<String> result = new HashSet<String>();
192
193
194 getReadableProperties(beanType, result, exploredTypes);
195
196
197 result.remove("class");
198
199 return result;
200 }
201
202
203
204
205
206
207
208
209 public static Set<String> getWriteableProperties(Class<?> beanType) {
210 Set<Class<?>> exploredTypes = new HashSet<Class<?>>();
211 Set<String> result = new HashSet<String>();
212
213
214 getWriteableProperties(beanType, result, exploredTypes);
215
216 return result;
217 }
218
219
220
221
222
223
224
225
226
227 public static boolean isNestedReadableProperty(Class<?> beanType, String propertyName) {
228 boolean result = propertyName.contains(".");
229 if (result) {
230 int dotIndex = propertyName.indexOf(".");
231 String firstLevelProperty = propertyName.substring(0, dotIndex);
232
233 Class<?> nestedType = getReadableType(beanType, firstLevelProperty);
234 if (nestedType == null) {
235
236 result = false;
237 } else {
238
239 String rest = propertyName.substring(dotIndex + 1);
240 result = isNestedReadableProperty(nestedType, rest);
241 }
242
243 } else {
244
245
246 Class<?> nestedType = getReadableType(beanType, propertyName);
247 result = nestedType != null;
248 }
249
250 return result;
251 }
252
253 public static Class<?> getReadableType(Class<?> beanType, String propertyName) {
254 PropertyDescriptor[] descriptors =
255 PropertyUtils.getPropertyDescriptors(beanType);
256
257 Class<?> result = null;
258 for (PropertyDescriptor descriptor : descriptors) {
259 String name = descriptor.getName();
260 if (descriptor.getReadMethod() != null &&
261 propertyName.equals(name)) {
262 result = descriptor.getReadMethod().getReturnType();
263 break;
264 }
265 }
266
267 if (result == null) {
268
269
270 if (beanType.getSuperclass() != null) {
271
272
273 result = getReadableType(beanType.getSuperclass(), propertyName);
274 }
275 }
276
277 if (result == null) {
278
279
280 Class<?>[] interfaces = beanType.getInterfaces();
281 for (Class<?> anInterface : interfaces) {
282
283 result = getReadableType(anInterface, propertyName);
284
285 if (result != null) {
286
287
288 break;
289 }
290 }
291 }
292 return result;
293 }
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308 public static Set<PropertyDescriptor> getDescriptors(Class<?> beanType,
309 Predicate<PropertyDescriptor> predicate) {
310
311 if (predicate == null) {
312 predicate = Predicates.alwaysTrue();
313 }
314
315 Set<Class<?>> exploredTypes = new HashSet<Class<?>>();
316 Map<String, PropertyDescriptor> result = new TreeMap<String, PropertyDescriptor>();
317
318 getDescriptors(beanType, predicate, result, exploredTypes);
319
320
321 result.remove("class");
322
323 return new HashSet<PropertyDescriptor>(result.values());
324 }
325
326 public static Method getMutator(Object bean, String property) {
327 Method mutator = null;
328 if (bean == null) {
329 throw new NullPointerException("could not find bean");
330 }
331 if (property == null) {
332 throw new NullPointerException("could not find property");
333 }
334
335 try {
336 PropertyDescriptor descriptor = PropertyUtils.getPropertyDescriptor(bean, property);
337 if (descriptor != null) {
338 mutator = descriptor.getWriteMethod();
339 }
340 } catch (Exception e) {
341 throw new RuntimeException(e);
342 }
343
344 return mutator;
345 }
346
347 protected static void getDescriptors(Class<?> beanType,
348 Predicate<PropertyDescriptor> predicate,
349 Map<String, PropertyDescriptor> result,
350 Set<Class<?>> exploredTypes) {
351
352 if (exploredTypes.contains(beanType)) {
353
354
355 return;
356 }
357 exploredTypes.add(beanType);
358
359 PropertyDescriptor[] descriptors =
360 PropertyUtils.getPropertyDescriptors(beanType);
361
362 for (PropertyDescriptor descriptor : descriptors) {
363 String name = descriptor.getName();
364 if (!result.containsKey(name) && predicate.apply(descriptor)) {
365 result.put(name, descriptor);
366 }
367 }
368
369 if (beanType.getSuperclass() != null) {
370
371
372 getDescriptors(beanType.getSuperclass(), predicate, result, exploredTypes);
373 }
374 Class<?>[] interfaces = beanType.getInterfaces();
375 for (Class<?> anInterface : interfaces) {
376
377
378 getDescriptors(anInterface, predicate, result, exploredTypes);
379 }
380 }
381
382 protected static void getReadableProperties(Class<?> beanType,
383 Set<String> result,
384 Set<Class<?>> exploredTypes) {
385
386 if (exploredTypes.contains(beanType)) {
387
388
389 return;
390 }
391 exploredTypes.add(beanType);
392
393
394 getReadableProperties(beanType, result);
395
396 if (beanType.getSuperclass() != null) {
397
398
399 getReadableProperties(beanType.getSuperclass(), result, exploredTypes);
400 }
401 Class<?>[] interfaces = beanType.getInterfaces();
402 for (Class<?> anInterface : interfaces) {
403
404
405 getReadableProperties(anInterface, result, exploredTypes);
406 }
407 }
408
409 protected static void getReadableProperties(Class<?> beanType,
410 Set<String> result) {
411
412 PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors(beanType);
413 for (PropertyDescriptor descriptor : descriptors) {
414 String name = descriptor.getName();
415 if (descriptor.getReadMethod() != null) {
416 result.add(name);
417 }
418 }
419 }
420
421 protected static void getWriteableProperties(Class<?> beanType,
422 Set<String> result,
423 Set<Class<?>> exploredTypes) {
424
425 if (exploredTypes.contains(beanType)) {
426
427
428 return;
429 }
430 exploredTypes.add(beanType);
431
432
433 getWriteableProperties(beanType, result);
434
435 if (beanType.getSuperclass() != null) {
436
437
438 getWriteableProperties(beanType.getSuperclass(), result, exploredTypes);
439 }
440 Class<?>[] interfaces = beanType.getInterfaces();
441 for (Class<?> anInterface : interfaces) {
442
443
444 getWriteableProperties(anInterface, result, exploredTypes);
445 }
446 }
447
448 protected static void getWriteableProperties(Class<?> beanType,
449 Set<String> result) {
450
451 PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors(beanType);
452 for (PropertyDescriptor descriptor : descriptors) {
453 String name = descriptor.getName();
454 if (descriptor.getWriteMethod() != null) {
455 result.add(name);
456 }
457 }
458 }
459 }