Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
Formatter |
|
| 4.037037037037037;4.037 |
1 | /* | |
2 | * Copyright 2006-2011 The Kuali Foundation | |
3 | * | |
4 | * Licensed under the Educational Community License, Version 2.0 (the "License"); | |
5 | * you may not use this file except in compliance with the License. | |
6 | * You may obtain a copy of the License at | |
7 | * | |
8 | * http://www.opensource.org/licenses/ecl2.php | |
9 | * | |
10 | * Unless required by applicable law or agreed to in writing, software | |
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
13 | * See the License for the specific language governing permissions and | |
14 | * limitations under the License. | |
15 | */ | |
16 | // begin Kuali Foundation modification | |
17 | package org.kuali.rice.core.web.format; | |
18 | // end Kuali Foundation modification | |
19 | ||
20 | import org.apache.commons.beanutils.PropertyUtils; | |
21 | import org.apache.commons.lang.StringUtils; | |
22 | import org.kuali.rice.core.util.ArrayUtils; | |
23 | import org.kuali.rice.core.util.type.AbstractKualiDecimal; | |
24 | import org.kuali.rice.core.util.type.KualiDecimal; | |
25 | import org.kuali.rice.core.util.type.KualiInteger; | |
26 | import org.kuali.rice.core.util.type.KualiPercent; | |
27 | ||
28 | import javax.servlet.http.HttpServletRequest; | |
29 | import java.io.Serializable; | |
30 | import java.lang.reflect.Array; | |
31 | import java.math.BigDecimal; | |
32 | import java.sql.Date; | |
33 | import java.sql.Timestamp; | |
34 | import java.util.*; | |
35 | ||
36 | ||
37 | ||
38 | // begin Kuali Foundation modification | |
39 | /** | |
40 | * This is the base class for all other Formatters. | |
41 | */ | |
42 | /** | |
43 | * It provides default formatting and conversion behavior for most value types, including primitives, arrays, and instances of most | |
44 | * {@link Collection}types. <code>Formatter</code> and its subclasses were designed primarily to be used by web app framework | |
45 | * components, though they can also be used in other contexts. | |
46 | * <p> | |
47 | * During request processing, the {@link PojoActionForm}uses <code>Formatter</code> instances to convert inbound request values | |
48 | * to JavaBean property types. Whenever a given value cannot be converted to its target type, the conversion method | |
49 | * {@link PropertyUtils#getProperty(Object, String)}throws a {@link FormatException}to signal this condition to the | |
50 | * calling code. | |
51 | * <p> | |
52 | * During the response phase, Struts tags make calls to the {@link PojoRequestProcessor}in order to access bean property values. | |
53 | * The <code>PojoRequestProcessor</code> then uses <code>Formatter</code> instances to format the bean values for presentation | |
54 | * in the user interface. | |
55 | * <p> | |
56 | * In either case, <code>Formatter</code> instances are obtained by calling {@link #getFormatter(Class)}, which looks in an | |
57 | * internal registry to determine which <code>Formatter</code> class to instantiate, and returns a new instance. The StrutsLive | |
58 | * framework includes a number of <code>Formatter</code> classes that are registered statically; additional | |
59 | * <code>Formatter classes can be registered at compile | |
60 | * time or at run time. | |
61 | * <p> | |
62 | * Subclasses of <code>Formatter</code> typically override the callback methods | |
63 | * {@link #convertToObject(String)} and {@link #formatObject(Object)}, which | |
64 | * otherwise provide default conversion and formmating behavior needed for | |
65 | * atomic values (i.e., an ordinary bean property such as a <code>String</code> | |
66 | * or <code>Integer</code>, or else an element of a property typed as | |
67 | * array or Collection). | |
68 | * | |
69 | * @see PojoActionForm#populate(HttpServletRequest) | |
70 | * @see PojoPropertyUtilsBean#getProperty(Object, String) | |
71 | */ | |
72 | // end Kuali Foundation modification | |
73 | 0 | public class Formatter implements Serializable { |
74 | // begin Kuali Foundation modification | |
75 | // removed serialVersionUID and logger members | |
76 | // end Kuali Foundation modification | |
77 | ||
78 | static final String CREATE_MSG = "Couldn't create an instance of class "; | |
79 | // begin Kuali Foundation modification | |
80 | // registry changed from AppLocal instance to a Map | |
81 | 0 | private static Map registry = Collections.synchronizedMap(new HashMap()); |
82 | // end Kuali Foundation modification | |
83 | ||
84 | protected Map settings; | |
85 | ||
86 | // begin Kuali Foundation modification | |
87 | // removed keypath and rootObject variables | |
88 | // end Kuali Foundation modification | |
89 | ||
90 | protected Class propertyType; | |
91 | ||
92 | static { | |
93 | // begin Kuali Foundation modification | |
94 | 0 | registerFormatter(String.class, Formatter.class); |
95 | 0 | registerFormatter(String[].class, Formatter.class); |
96 | 0 | registerFormatter(AbstractKualiDecimal.class, BigDecimalFormatter.class); |
97 | 0 | registerFormatter(KualiDecimal.class, CurrencyFormatter.class); |
98 | 0 | registerFormatter(KualiInteger.class, KualiIntegerCurrencyFormatter.class); |
99 | 0 | registerFormatter(KualiPercent.class, PercentageFormatter.class); |
100 | 0 | registerFormatter(BigDecimal.class, BigDecimalFormatter.class); |
101 | 0 | registerFormatter(Date.class, DateFormatter.class); |
102 | 0 | registerFormatter(Integer.class, IntegerFormatter.class); |
103 | 0 | registerFormatter(int.class, IntegerFormatter.class); |
104 | 0 | registerFormatter(int[].class, IntegerFormatter.class); |
105 | 0 | registerFormatter(Boolean.class, BooleanFormatter.class); |
106 | 0 | registerFormatter(Boolean.TYPE, BooleanFormatter.class); |
107 | 0 | registerFormatter(boolean[].class, BooleanFormatter.class); |
108 | 0 | registerFormatter(Long.class, LongFormatter.class); |
109 | 0 | registerFormatter(Timestamp.class, DateViewTimestampObjectFormatter.class); |
110 | 0 | registerFormatter(boolean.class, LittleBooleanFormatter.class); |
111 | 0 | registerFormatter(Collection.class, ArrayFormatter.class); |
112 | // end Kuali Foundation modification | |
113 | 0 | } |
114 | ||
115 | public static Formatter getFormatter(Class aType) { | |
116 | 0 | return getFormatter(aType, null); |
117 | } | |
118 | ||
119 | // begin Kuali Foundation modification | |
120 | // param aType was valueType, comment changes, major code changes | |
121 | /** | |
122 | * Returns an instance of the Formatter class to be used to format the provided value type. | |
123 | * | |
124 | * @param type the class of the value to be formatted | |
125 | * @param settings parameters used by subclasses to customize behavior | |
126 | * @return an instance of Formatter or one of its subclasses | |
127 | */ | |
128 | public static Formatter getFormatter(Class aType, Map settings) { | |
129 | // original code: return createFormatter(formatterForType(valueType), valueType, settings); | |
130 | ||
131 | 0 | Class type = formatterForType(aType); |
132 | 0 | Formatter formatter = null; |
133 | try { | |
134 | 0 | formatter = (Formatter) type.newInstance(); |
135 | } | |
136 | 0 | catch (InstantiationException e) { |
137 | 0 | throw new FormatException(CREATE_MSG + type, e); |
138 | } | |
139 | 0 | catch (IllegalAccessException e) { |
140 | 0 | throw new FormatException(CREATE_MSG + type, e); |
141 | 0 | } |
142 | ||
143 | 0 | if (settings != null) |
144 | 0 | formatter.setSettings(Collections.unmodifiableMap(settings)); |
145 | 0 | formatter.propertyType = aType; |
146 | ||
147 | 0 | return formatter; |
148 | } | |
149 | ||
150 | // removed getFormatterByName, formatterClassForName, createFormatter methods | |
151 | // end Kuali Foundation modification | |
152 | ||
153 | /** | |
154 | * Binds the provided value type to a Formatter type. Note that a single Formatter class can be associated with more than one | |
155 | * type. | |
156 | * | |
157 | * @param type a value type | |
158 | * @param formatterType a Formatter type | |
159 | */ | |
160 | public static void registerFormatter(Class type, Class formatterType) { | |
161 | 0 | registry.put(type, formatterType); |
162 | 0 | } |
163 | ||
164 | /** | |
165 | * Returns <code>true</code> if the provided class is an array type, implements either the {@link List}or {@link Set} | |
166 | * interfaces, or is one of the Formatter classes currently registered. | |
167 | * | |
168 | * @see registerFormatter(Class, Class) | |
169 | */ | |
170 | public static boolean isSupportedType(Class type) { | |
171 | // begin Kuali Foundation modification | |
172 | 0 | if (type == null) |
173 | 0 | return false; |
174 | // end Kuali Foundation modification | |
175 | 0 | if (List.class.isAssignableFrom(type)) |
176 | 0 | return true; |
177 | 0 | if (Set.class.isAssignableFrom(type)) |
178 | 0 | return true; |
179 | ||
180 | 0 | return findFormatter(type) != null; |
181 | } | |
182 | ||
183 | /** | |
184 | * Return the Formatter associated with the given type, by consulting an internal registry. Additional associations can be made | |
185 | * by calling {@link registerFormatter(Class, Class)}. | |
186 | * | |
187 | * @return a new Formatter instance | |
188 | */ | |
189 | public static Class formatterForType(Class type) { | |
190 | 0 | if (type == null) |
191 | 0 | throw new IllegalArgumentException("Type can not be null"); |
192 | ||
193 | 0 | Class formatterType = findFormatter(type); |
194 | ||
195 | 0 | return formatterType == null ? Formatter.class : formatterType; |
196 | } | |
197 | ||
198 | // Kuali Foundation modification: comment removed | |
199 | public static Class findFormatter(Class type) { | |
200 | // begin Kuali Foundation modification | |
201 | 0 | if (type == null) |
202 | 0 | return null; |
203 | ||
204 | 0 | if (registry.containsKey(type)) { |
205 | 0 | return (Class) registry.get(type); |
206 | } | |
207 | ||
208 | ||
209 | 0 | Iterator typeIter = registry.keySet().iterator(); |
210 | 0 | while (typeIter.hasNext()) { |
211 | 0 | Class currType = (Class) typeIter.next(); |
212 | 0 | if (currType.isAssignableFrom(type)) { |
213 | 0 | Class currFormatter = (Class) registry.get(currType); |
214 | 0 | registerFormatter(type, currFormatter); |
215 | 0 | return currFormatter; |
216 | } | |
217 | 0 | } |
218 | ||
219 | 0 | return null; |
220 | // end Kuali Foundation modification | |
221 | } | |
222 | ||
223 | // begin Kuali Foundation modification | |
224 | public String getImplementationClass() { | |
225 | 0 | return this.getClass().getName(); |
226 | } | |
227 | // end Kuali Foundation modification | |
228 | ||
229 | public Class getPropertyType() { | |
230 | 0 | return propertyType; |
231 | } | |
232 | ||
233 | public void setPropertyType(Class propertyType) { | |
234 | 0 | this.propertyType = propertyType; |
235 | 0 | } |
236 | ||
237 | public Map getSettings() { | |
238 | 0 | return settings; |
239 | } | |
240 | ||
241 | public void setSettings(Map settings) { | |
242 | 0 | this.settings = settings; |
243 | 0 | } |
244 | ||
245 | // begin Kuali Foundation modification | |
246 | // removed getKeypath, setKeyPath, getRootObject, setRootObject, hasSettingForKey, settingForKey, typeForKey, getErrorKey | |
247 | // end Kuali Foundation modification | |
248 | ||
249 | /** | |
250 | * begin Kuali Foundation modification | |
251 | * Returns a String representation of the given value. May be overridden by subclasses to provide customized behavior for | |
252 | * different types, though generally the callback method {@link #format(Object)}provides a better customization hook. | |
253 | * <p> | |
254 | * Provides default handling for properties typed as array or Collection. Subclass implementations of this method must invoke | |
255 | * <code>super.formatForPresentation()</code> to take advantage of this built-in behavior. | |
256 | * <p> | |
257 | * Delegates to callback method {@link formatObject}for all other types. This method in turn invokes the callback method | |
258 | * <code>format</code>, which serves as an extension point for subclasses; the default implementation simply returns its | |
259 | * argument. Overriding <code>format</code> allows subclasses to take advantage of all of the array, primitive type, and | |
260 | * Collection handling functionality provided by the base class. | |
261 | * | |
262 | * @param value the object to be formatted | |
263 | * @return a formatted string representation of the given object | |
264 | * @see #formatObject(Object) | |
265 | * end Kuali Foundation modification | |
266 | */ | |
267 | public Object formatForPresentation(Object value) { | |
268 | 0 | if (isNullValue(value)) |
269 | 0 | return formatNull(); |
270 | ||
271 | // begin Kuali Foundation modification | |
272 | // removed code | |
273 | /* | |
274 | // TODO: add registry for non-navigable classes so there's a way to | |
275 | // disable formatting selectively for given types contained in arrays | |
276 | // or Collections. | |
277 | if (Collection.class.isAssignableFrom(value.getClass())) | |
278 | return formatCollection((Collection) value); | |
279 | | |
280 | if (propertyType != null && propertyType.isArray()) | |
281 | return formatArray(value); | |
282 | */ | |
283 | // end Kuali Foundation modification | |
284 | ||
285 | 0 | return formatObject(value); |
286 | } | |
287 | ||
288 | /** | |
289 | * May be overridden by subclasses to provide special handling for <code>null</code> values when formatting a bean property | |
290 | * value for presentation. The default implementation simply returns <code>null</code> | |
291 | */ | |
292 | protected Object formatNull() { | |
293 | 0 | return null; |
294 | } | |
295 | ||
296 | /** | |
297 | * May be overridden by subclasses to provide custom formatting behavior. Provides default formatting implementation for | |
298 | * primitive types. (Note that primitive types are will always be wrapped in an array in order to be passed as an argument of | |
299 | * type <code>Object</code>). | |
300 | */ | |
301 | public Object formatObject(Object value) { | |
302 | 0 | if (value == null) |
303 | 0 | return formatNull(); |
304 | ||
305 | // Collections and arrays have already been handled at this point, so | |
306 | // if value is an array, assume it's a wrapper for a primitive type. | |
307 | 0 | Class<?> type = value.getClass(); |
308 | 0 | if (type.isArray()) |
309 | // begin Kuali Foundation modification | |
310 | 0 | return ArrayUtils.toString(value, type.getComponentType()); |
311 | // end begin Kuali Foundation modification | |
312 | ||
313 | 0 | if (!(isSupportedType(value.getClass()))) |
314 | // begin Kuali Foundation modification | |
315 | 0 | formatBean(value); |
316 | // end Kuali Foundation modification | |
317 | ||
318 | 0 | return format(value); |
319 | } | |
320 | ||
321 | /** | |
322 | * If an element of the Collection isn't a supported type, assume it's a JavaBean, and format each of its properties. Returns a | |
323 | * Map containing the formatted properties keyed by property name. | |
324 | */ | |
325 | protected Object formatBean(Object bean) { | |
326 | 0 | Map properties = null; |
327 | try { | |
328 | // begin Kuali Foundation modification | |
329 | 0 | properties = PropertyUtils.describe(bean); |
330 | // end Kuali Foundation modification | |
331 | } | |
332 | 0 | catch (Exception e) { |
333 | 0 | throw new FormatException("Unable to format values for bean " + bean, e); |
334 | 0 | } |
335 | ||
336 | 0 | Map formattedVals = new HashMap(); |
337 | // begin Kuali Foundation modification | |
338 | 0 | Iterator propIter = properties.entrySet().iterator(); |
339 | ||
340 | 0 | while (propIter.hasNext()) { |
341 | 0 | Map.Entry entry = (Map.Entry) propIter.next(); |
342 | 0 | Object value = entry.getValue(); |
343 | 0 | if (value != null && isSupportedType(value.getClass())) { |
344 | 0 | Formatter formatter = getFormatter(value.getClass()); |
345 | 0 | formattedVals.put(entry.getKey(), formatter.formatForPresentation(value)); |
346 | } | |
347 | 0 | } |
348 | // end Kuali Foundation modification | |
349 | 0 | return formattedVals; |
350 | } | |
351 | ||
352 | public Object format(Object value) { | |
353 | 0 | return value; |
354 | } | |
355 | ||
356 | public Object formatArray(Object value) { | |
357 | // begin Kuali Foundation modification | |
358 | 0 | Class elementType = value.getClass().getComponentType(); |
359 | 0 | if (!isSupportedType(elementType)) |
360 | 0 | return value; |
361 | ||
362 | 0 | int length = Array.getLength(value); |
363 | 0 | Object[] formattedVals = new String[length]; |
364 | ||
365 | 0 | for (int i = 0; i < length; i++) { |
366 | 0 | Object element = Array.get(value, i); |
367 | 0 | Object objValue = ArrayUtils.toObject(element); |
368 | 0 | Formatter elementFormatter = getFormatter(elementType); |
369 | 0 | formattedVals[i] = elementFormatter.formatForPresentation(objValue); |
370 | } | |
371 | ||
372 | 0 | return formattedVals; |
373 | // end Kuali Foundation modification | |
374 | } | |
375 | ||
376 | public Object formatCollection(Collection value) { | |
377 | 0 | List stringVals = new ArrayList(); |
378 | 0 | Iterator iter = value.iterator(); |
379 | 0 | while (iter.hasNext()) { |
380 | 0 | Object obj = iter.next(); |
381 | 0 | Formatter formatter = getFormatter(obj.getClass()); |
382 | // begin Kuali Foundation modification | |
383 | 0 | stringVals.add(formatter.formatForPresentation(obj)); |
384 | // end Kuali Foundation modification | |
385 | 0 | } |
386 | 0 | return stringVals.toArray(); |
387 | } | |
388 | ||
389 | /** | |
390 | * Returns an object representation of the provided string after first removing any extraneous formatting characters. If the | |
391 | * argument is a native array wrapping the actual value, the value is removed (unwrapped) from the array prior to invoking the | |
392 | * callback method {@link #convertToObject(String)}, which performs the actual conversion. | |
393 | * <p> | |
394 | * If the provided object is <code>null</code>, a blank <code>String</code>, or a <code>String[]</code> of length <b>0 | |
395 | * </b> or that has <code>null</code> or a blank <code>String</code> in the first position, returns <code>null</code>. | |
396 | * Otherwise, If the destination property is a <code>Collection</code>, returns an instance of that type containing the | |
397 | * string values of the array elements. | |
398 | * <p> | |
399 | * If the provided object is an array, uses a Formatter corresponding to the array's component type to convert each of its | |
400 | * elements, and returns a new array containing the converted values. | |
401 | * | |
402 | * May be overidden by subclasses to customize conversion, though ordinarily {@link #convertToObject(String)}is a better choice | |
403 | * since it takes advantage of <code>convertFromPresentationFormat</code>'s built-in behavior. | |
404 | * | |
405 | * @param value the string value to be converted | |
406 | * @return the object value corresponding to the provided string value | |
407 | * @see convertToObject(String) | |
408 | */ | |
409 | public Object convertFromPresentationFormat(Object value) { | |
410 | 0 | if (isEmptyValue(value)) |
411 | 0 | return getNullObjectValue(); |
412 | ||
413 | 0 | Class type = value.getClass(); |
414 | 0 | boolean isArray = propertyType != null && propertyType.isArray(); |
415 | 0 | boolean isCollection = propertyType != null && Collection.class.isAssignableFrom(propertyType); |
416 | ||
417 | 0 | if (!(isArray || isCollection)) { |
418 | 0 | value = unwrapString(value); |
419 | 0 | return convertToObject((String) value); |
420 | } | |
421 | ||
422 | 0 | String[] strings = type.isArray() ? (String[]) value : new String[] { (String) value }; |
423 | ||
424 | 0 | return isArray ? convertToArray(strings) : convertToCollection(strings); |
425 | } | |
426 | ||
427 | /** | |
428 | * May be overridden by subclasses to provide special handling for <code>null</code> values when converting from presentation | |
429 | * format to a bean property type. The default implementation simply returns <code>null</code> | |
430 | */ | |
431 | protected Object getNullObjectValue() { | |
432 | 0 | return null; |
433 | } | |
434 | ||
435 | /** | |
436 | * May be orverridden by subclasses to customize its behavior. The default implementation simply trims and returns the provided | |
437 | * string. | |
438 | */ | |
439 | protected Object convertToObject(String string) { | |
440 | 0 | return string == null ? null : string.replace( "\r\n", "\n" ).trim(); |
441 | } | |
442 | ||
443 | /** | |
444 | * Converts an array of strings to a Collection type corresponding to the value of <code>propertyType</code>. Since we don't | |
445 | * have type information for the elements of the collection, no attempt is made to convert the elements from <code>String</code> | |
446 | * to other types. However, subclasses can override this method if they need to provide the ability to convert the elements to a | |
447 | * given type. | |
448 | */ | |
449 | protected Collection convertToCollection(String[] strings) { | |
450 | 0 | Collection collection = null; |
451 | 0 | Class type = propertyType; |
452 | ||
453 | 0 | if (propertyType.isAssignableFrom(List.class)) |
454 | 0 | type = ArrayList.class; |
455 | 0 | else if (propertyType.isAssignableFrom(Set.class)) |
456 | 0 | type = HashSet.class; |
457 | ||
458 | try { | |
459 | 0 | collection = (Collection) type.newInstance(); |
460 | } | |
461 | 0 | catch (Exception e) { |
462 | 0 | throw new FormatException(CREATE_MSG + propertyType, e); |
463 | 0 | } |
464 | ||
465 | 0 | for (int i = 0; i < strings.length; i++) |
466 | 0 | collection.add(strings[i]); |
467 | ||
468 | 0 | return collection; |
469 | } | |
470 | ||
471 | /** | |
472 | * Converts an array of strings to an array of objects by calling {@link #convertToObject(String)}on each element of the | |
473 | * provided array in turn, using instances of a Formatter class that corresponds to this Formatter's property type. | |
474 | * | |
475 | * @see #propertyType | |
476 | */ | |
477 | protected Object convertToArray(String[] strings) { | |
478 | 0 | Class type = propertyType.getComponentType(); |
479 | // begin Kuali Foundation modification | |
480 | 0 | Formatter formatter = getFormatter(type); |
481 | // end Kuali Foundation modification | |
482 | 0 | Object array = null; |
483 | try { | |
484 | 0 | array = Array.newInstance(type, strings.length); |
485 | } | |
486 | 0 | catch (Exception e) { |
487 | 0 | throw new FormatException(CREATE_MSG + type, e); |
488 | 0 | } |
489 | ||
490 | 0 | for (int i = 0; i < strings.length; i++) { |
491 | 0 | Object value = formatter.convertToObject(strings[i]); |
492 | // begin Kuali Foundation modification | |
493 | 0 | ArrayUtils.setArrayValue(array, type, value, i); |
494 | // end Kuali Foundation modification | |
495 | } | |
496 | ||
497 | 0 | return array; |
498 | } | |
499 | ||
500 | public static String unwrapString(Object target) { | |
501 | ||
502 | 0 | if (target.getClass().isArray()) { |
503 | 0 | String wrapper[] = (String[]) target; |
504 | 0 | return wrapper.length > 0 ? wrapper[0] : null; |
505 | } | |
506 | // begin Kuali Foundation modification | |
507 | // if target object is null, return a null String | |
508 | 0 | else if (target == null) { |
509 | 0 | return new String(); |
510 | } | |
511 | ||
512 | // otherwise, return the string value of the object, with the hope | |
513 | // that the toString() has been meaningfully overriden | |
514 | else { | |
515 | 0 | return target.toString(); |
516 | } | |
517 | // end Kuali Foundation modification | |
518 | } | |
519 | ||
520 | public static boolean isNullValue(Object obj) { | |
521 | 0 | if (obj == null) |
522 | 0 | return true; |
523 | ||
524 | // begin Kuali Foundation modification | |
525 | 0 | if ((obj instanceof String) && StringUtils.isEmpty((String) obj)) |
526 | 0 | return true; |
527 | // end Kuali Foundation modification | |
528 | ||
529 | 0 | return false; |
530 | } | |
531 | ||
532 | public static boolean isEmptyValue(Object obj) { | |
533 | 0 | if (obj == null) |
534 | 0 | return true; |
535 | // begin Kuali Foundation modification | |
536 | 0 | if ((obj instanceof String) && StringUtils.isEmpty((String) obj)) |
537 | 0 | return true; |
538 | // end Kuali Foundation modification | |
539 | 0 | Class type = obj.getClass(); |
540 | 0 | if (type.isArray()) { |
541 | 0 | Class compType = type.getComponentType(); |
542 | 0 | if (compType.isPrimitive()) |
543 | 0 | return false; |
544 | 0 | if (((Object[]) obj).length == 0) |
545 | 0 | return true; |
546 | 0 | if (((Object[]) obj)[0] == null) |
547 | 0 | return true; |
548 | 0 | if (String.class.isAssignableFrom(compType)) { |
549 | // begin Kuali Foundation modification | |
550 | 0 | return StringUtils.isEmpty(((String[]) obj)[0]); |
551 | // end Kuali Foundation modification | |
552 | } | |
553 | } | |
554 | 0 | return false; |
555 | } | |
556 | ||
557 | protected String trimString(Object target) { | |
558 | 0 | String stringValue = null; |
559 | try { | |
560 | 0 | stringValue = (String) target; |
561 | } | |
562 | 0 | catch (ClassCastException e) { |
563 | 0 | throw new FormatException("Can't cast " + target + " to String", e); |
564 | 0 | } |
565 | 0 | return stringValue == null ? null : stringValue.trim(); |
566 | } | |
567 | } |