Coverage Report - org.kuali.rice.core.web.format.Formatter
 
Classes in this File Line Coverage Branch Coverage Complexity
Formatter
0%
0/183
0%
0/100
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  
 }