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