| 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 | }  |