1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.kuali.rice.kns.web.struts.form.pojo;
18
19 import org.apache.commons.beanutils.MappedPropertyDescriptor;
20 import org.apache.commons.beanutils.NestedNullException;
21 import org.apache.commons.beanutils.PropertyUtils;
22 import org.apache.commons.beanutils.PropertyUtilsBean;
23 import org.apache.commons.collections.FastHashMap;
24 import org.apache.log4j.Logger;
25 import org.kuali.rice.core.web.format.Formatter;
26 import org.kuali.rice.krad.util.ObjectUtils;
27
28 import java.beans.IntrospectionException;
29 import java.beans.PropertyDescriptor;
30 import java.lang.reflect.InvocationTargetException;
31 import java.lang.reflect.Method;
32 import java.util.Map;
33
34
35
36
37
38
39
40
41
42 public class PojoPropertyUtilsBean extends PropertyUtilsBean {
43
44 public static final Logger LOG = Logger.getLogger(PojoPropertyUtilsBean.class.getName());
45
46
47 public PojoPropertyUtilsBean() {
48 super();
49 }
50
51
52 public Object getProperty(Object bean, String key) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
53
54 if (!(bean instanceof PojoForm))
55 return super.getProperty(bean, key);
56
57 PojoForm form = (PojoForm) bean;
58 Map unconvertedValues = form.getUnconvertedValues();
59
60 if (unconvertedValues.containsKey(key))
61 return unconvertedValues.get(key);
62
63 Object val = getNestedProperty(bean, key);
64 Class type = (val!=null)?val.getClass():null;
65 if ( type == null ) {
66 try {
67 type = getPropertyType(bean, key);
68 } catch ( Exception ex ) {
69 type = String.class;
70 LOG.warn( "Unable to get property type for Class: " + bean.getClass().getName() + "/Property: " + key );
71 }
72 }
73 return (Formatter.isSupportedType(type) ? form.formatValue(val, key, type) : val);
74
75 }
76
77
78
79
80
81
82
83
84 public Object getNestedProperty(Object arg0, String arg1) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
85
86 try {
87 return super.getNestedProperty(arg0, arg1);
88 }
89 catch (NestedNullException e) {
90 return "";
91 }
92 catch (InvocationTargetException e1) {
93 return "";
94 }
95
96
97 }
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116 public void setNestedProperty(Object bean, String name, Object value) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
117
118 if (bean == null) {
119 if (LOG.isDebugEnabled()) LOG.debug("No bean specified, name = " + name + ", value = " + value);
120 return;
121 }
122 if (name == null) {
123 throw new IllegalArgumentException("No name specified");
124 }
125
126 Object propBean = null;
127 int indexOfINDEXED_DELIM = -1;
128 int indexOfMAPPED_DELIM = -1;
129 while (true) {
130 int delim = name.indexOf(PropertyUtils.NESTED_DELIM);
131 if (delim < 0) {
132 break;
133 }
134 String next = name.substring(0, delim);
135 indexOfINDEXED_DELIM = next.indexOf(PropertyUtils.INDEXED_DELIM);
136 indexOfMAPPED_DELIM = next.indexOf(PropertyUtils.MAPPED_DELIM);
137 if (bean instanceof Map) {
138 propBean = ((Map) bean).get(next);
139 }
140 else if (indexOfMAPPED_DELIM >= 0) {
141 propBean = getMappedProperty(bean, next);
142 }
143 else if (indexOfINDEXED_DELIM >= 0) {
144 propBean = getIndexedProperty(bean, next);
145 }
146 else {
147 propBean = getSimpleProperty(bean, next);
148 }
149 if (ObjectUtils.isNull(propBean)) {
150 Class propertyType = getPropertyType(bean, next);
151 if (propertyType != null) {
152 Object newInstance = ObjectUtils.createNewObjectFromClass(propertyType);
153 setSimpleProperty(bean, next, newInstance);
154 propBean = getSimpleProperty(bean, next);
155 }
156 }
157 bean = propBean;
158 name = name.substring(delim + 1);
159 }
160
161 indexOfINDEXED_DELIM = name.indexOf(PropertyUtils.INDEXED_DELIM);
162 indexOfMAPPED_DELIM = name.indexOf(PropertyUtils.MAPPED_DELIM);
163
164 if (bean instanceof Map) {
165
166 PropertyDescriptor descriptor = getPropertyDescriptor(bean, name);
167 if (descriptor == null) {
168
169 ((Map) bean).put(name, value);
170 }
171 else {
172
173 setSimpleProperty(bean, name, value);
174 }
175 }
176 else if (indexOfMAPPED_DELIM >= 0) {
177 setMappedProperty(bean, name, value);
178 }
179 else if (indexOfINDEXED_DELIM >= 0) {
180 setIndexedProperty(bean, name, value);
181 }
182 else {
183 setSimpleProperty(bean, name, value);
184 }
185 }
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210 public PropertyDescriptor getPropertyDescriptor(Object bean, String name) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
211 if (bean == null) {
212 if (LOG.isDebugEnabled()) LOG.debug("No bean specified, name = " + name);
213 return null;
214 }
215 if (name == null) {
216 throw new IllegalArgumentException("No name specified");
217 }
218 try {
219
220 Object propBean = null;
221 while (true) {
222 int delim = findNextNestedIndex(name);
223
224 if (delim < 0) {
225 break;
226 }
227 String next = name.substring(0, delim);
228 int indexOfINDEXED_DELIM = next.indexOf(PropertyUtils.INDEXED_DELIM);
229 int indexOfMAPPED_DELIM = next.indexOf(PropertyUtils.MAPPED_DELIM);
230 if (indexOfMAPPED_DELIM >= 0 && (indexOfINDEXED_DELIM < 0 || indexOfMAPPED_DELIM < indexOfINDEXED_DELIM)) {
231 propBean = getMappedProperty(bean, next);
232 }
233 else {
234 if (indexOfINDEXED_DELIM >= 0) {
235 propBean = getIndexedProperty(bean, next);
236 }
237 else {
238 propBean = getSimpleProperty(bean, next);
239 }
240 }
241 if (ObjectUtils.isNull(propBean)) {
242 Class propertyType = getPropertyType(bean, next);
243 if (propertyType != null) {
244 Object newInstance = ObjectUtils.createNewObjectFromClass(propertyType);
245 setSimpleProperty(bean, next, newInstance);
246 propBean = getSimpleProperty(bean, next);
247 }
248 }
249 bean = propBean;
250 name = name.substring(delim + 1);
251 }
252
253
254 int left = name.indexOf(PropertyUtils.INDEXED_DELIM);
255 if (left >= 0) {
256 name = name.substring(0, left);
257 }
258 left = name.indexOf(PropertyUtils.MAPPED_DELIM);
259 if (left >= 0) {
260 name = name.substring(0, left);
261 }
262
263
264
265 if ((bean == null) || (name == null)) {
266 return (null);
267 }
268
269 PropertyDescriptor descriptors[] = getPropertyDescriptors(bean);
270 if (descriptors != null) {
271
272 for (int i = 0; i < descriptors.length; i++) {
273 if (name.equals(descriptors[i].getName()))
274 return (descriptors[i]);
275 }
276 }
277
278 PropertyDescriptor result = null;
279 FastHashMap mappedDescriptors = getMappedPropertyDescriptors(bean);
280 if (mappedDescriptors == null) {
281 mappedDescriptors = new FastHashMap();
282 mappedDescriptors.setFast(true);
283 }
284 result = (PropertyDescriptor) mappedDescriptors.get(name);
285 if (result == null) {
286
287 try {
288 result = new MappedPropertyDescriptor(name, bean.getClass());
289 }
290 catch (IntrospectionException ie) {
291 }
292 if (result != null) {
293 mappedDescriptors.put(name, result);
294 }
295 }
296
297 return result;
298 } catch ( RuntimeException ex ) {
299 LOG.error( "Unable to get property descriptor for " + bean.getClass().getName() + " . " + name
300 + "\n" + ex.getClass().getName() + ": " + ex.getMessage() );
301 throw ex;
302 }
303 }
304
305
306 private int findNextNestedIndex(String expression)
307 {
308
309
310 int bracketCount = 0;
311 for (int i=0, size=expression.length(); i<size ; i++) {
312 char at = expression.charAt(i);
313 switch (at) {
314 case PropertyUtils.NESTED_DELIM:
315 if (bracketCount < 1) {
316 return i;
317 }
318 break;
319
320 case PropertyUtils.MAPPED_DELIM:
321 case PropertyUtils.INDEXED_DELIM:
322
323 ++bracketCount;
324 break;
325
326 case PropertyUtils.MAPPED_DELIM2:
327 case PropertyUtils.INDEXED_DELIM2:
328
329 --bracketCount;
330 break;
331 }
332 }
333
334 return -1;
335 }
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356 public void setSimpleProperty(Object bean,
357 String name, Object value)
358 throws IllegalAccessException, InvocationTargetException,
359 NoSuchMethodException {
360
361 if (bean == null) {
362 if (LOG.isDebugEnabled()) LOG.debug("No bean specified, name = " + name + ", value = " + value);
363 return;
364 }
365 if (name == null) {
366 throw new IllegalArgumentException("No name specified");
367 }
368
369
370 if (name.indexOf(PropertyUtils.NESTED_DELIM) >= 0) {
371 throw new IllegalArgumentException
372 ("Nested property names are not allowed");
373 } else if (name.indexOf(PropertyUtils.INDEXED_DELIM) >= 0) {
374 throw new IllegalArgumentException
375 ("Indexed property names are not allowed");
376 } else if (name.indexOf(PropertyUtils.MAPPED_DELIM) >= 0) {
377 throw new IllegalArgumentException
378 ("Mapped property names are not allowed");
379 }
380
381
382 PropertyDescriptor descriptor =
383 getPropertyDescriptor(bean, name);
384 if (descriptor == null) {
385 throw new NoSuchMethodException("Unknown property '" +
386 name + "'");
387 }
388 Method writeMethod = getWriteMethod(descriptor);
389 if (writeMethod == null) {
390
391 LOG.warn("Bean: " + bean.getClass().getName() + ", Property '" + name + "' has no setter method");
392 return;
393 }
394
395
396 Object values[] = new Object[1];
397 values[0] = value;
398 if (LOG.isDebugEnabled()) {
399 String valueClassName =
400 value == null ? "<null>" : value.getClass().getName();
401 LOG.debug("setSimpleProperty: Invoking method " + writeMethod
402 + " with value " + value + " (class " + valueClassName + ")");
403 }
404
405
406 invokeMethod(writeMethod, bean, values);
407
408 }
409
410
411 private Object invokeMethod(
412 Method method,
413 Object bean,
414 Object[] values)
415 throws
416 IllegalAccessException,
417 InvocationTargetException {
418 try {
419
420 return method.invoke(bean, values);
421
422 } catch (IllegalArgumentException e) {
423
424 LOG.error("Method invocation failed.", e);
425 throw new IllegalArgumentException(
426 "Cannot invoke " + method.getDeclaringClass().getName() + "."
427 + method.getName() + " - " + e.getMessage());
428
429 }
430 }
431
432 }