| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| BigDecimalFormatter | 
  | 
  | 8.5;8.5 | 
| 1 |  /* | |
| 2 |   * Copyright 2006-2008 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 |  package org.kuali.rice.core.web.format; | |
| 17 | ||
| 18 |  import java.math.BigDecimal; | |
| 19 |  import java.text.DecimalFormat; | |
| 20 |  import java.text.ParseException; | |
| 21 |  import java.util.regex.Pattern; | |
| 22 | ||
| 23 |  import org.apache.log4j.Logger; | |
| 24 |  import org.kuali.rice.core.util.RiceKeyConstants; | |
| 25 | ||
| 26 |  /** | |
| 27 |   * This class is used to format BigDecimal objects. | |
| 28 |   */ | |
| 29 | 0 |  public class BigDecimalFormatter extends Formatter { | 
| 30 | 0 |      private static Logger LOG = Logger.getLogger(BigDecimalFormatter.class); | 
| 31 | 0 |      private static final Pattern DECIMAL_PATTERN = Pattern.compile("\\-?[0-9,]*\\.?[0-9]*"); | 
| 32 | ||
| 33 |      /** | |
| 34 |       * Unformats its argument and returns a KualiDecimal instance initialized with the resulting string value | |
| 35 |       *  | |
| 36 |       * @see org.kuali.rice.core.web.format.Formatter#convertToObject(java.lang.String) | |
| 37 |       */ | |
| 38 |      protected Object convertToObject(String target) { | |
| 39 | 0 |          BigDecimal value = null; | 
| 40 | ||
| 41 | 0 |          LOG.debug("convertToObject '" + target + "'"); | 
| 42 | ||
| 43 | 0 |          if (target != null) { | 
| 44 | ||
| 45 |              // preemptively detect non-numeric-related symbols, since NumberFormat.parse seems to be silently deleting them | |
| 46 |              // (i.e. 9aaaaaaaaaaaaaaa is silently converted into 9) | |
| 47 | 0 |              if (!DECIMAL_PATTERN.matcher(target).matches()) { | 
| 48 | 0 |                  throw new FormatException("parsing", RiceKeyConstants.ERROR_NUMERIC, target); | 
| 49 | }  | |
| 50 | ||
| 51 | ||
| 52 |              // actually reformat the numeric value | |
| 53 | 0 |              DecimalFormat formatter = new DecimalFormat(); | 
| 54 | 0 |              formatter.setParseBigDecimal(true); | 
| 55 |              try { | |
| 56 | 0 |                  Number parsedNumber = formatter.parse(target); | 
| 57 | 0 |                  value = new BigDecimal(parsedNumber.toString()); | 
| 58 | }  | |
| 59 | 0 |              catch (NumberFormatException e) { | 
| 60 | 0 |                  throw new FormatException("parsing", RiceKeyConstants.ERROR_BIG_DECIMAL, target, e); | 
| 61 | }  | |
| 62 | 0 |              catch (ParseException e) { | 
| 63 | 0 |                  throw new FormatException("parsing", RiceKeyConstants.ERROR_BIG_DECIMAL, target, e); | 
| 64 | 0 |              } | 
| 65 | }  | |
| 66 | ||
| 67 | 0 |          return value; | 
| 68 | }  | |
| 69 | ||
| 70 | ||
| 71 | ||
| 72 |      /** | |
| 73 |       * Returns a string representation of its argument formatted as a decimal value. | |
| 74 |       *  | |
| 75 |       * @see org.kuali.rice.core.web.format.Formatter#format(java.lang.Object) | |
| 76 |       */ | |
| 77 |      public Object format(Object obj) { | |
| 78 | 0 |          LOG.debug("format '" + obj + "'"); | 
| 79 | 0 |          if (obj == null) | 
| 80 | 0 |              return null; | 
| 81 | ||
| 82 | 0 |          DecimalFormat formatter = new DecimalFormat(); | 
| 83 | 0 |          String string = null; | 
| 84 | ||
| 85 |          try { | |
| 86 | 0 |              BigDecimal number = (BigDecimal) obj; | 
| 87 | ||
| 88 | ||
| 89 | 0 |              if(number!=null && number.scale()>0) { | 
| 90 |                  //remember to force a scale (with whatever rounding) in your java object to enforce this | |
| 91 | 0 |                  formatter.setMinimumFractionDigits(number.scale()); | 
| 92 | } else {//arbitrary scale  | |
| 93 |                  //according to the api this line shouldn't be needed for BigDecimal and it should be | |
| 94 |                  //able to do arbitrary precision, however it didn't work in my tests it appears there  | |
| 95 |                  //is an open java bug that relates to this sun bug (sun BUG:5060859) and that's why | |
| 96 |                  //we may need this workaround for now | |
| 97 | 0 |                  formatter.setMaximumFractionDigits(340); | 
| 98 | }  | |
| 99 | 0 |              string = formatter.format(number); | 
| 100 | }  | |
| 101 | 0 |          catch (IllegalArgumentException e) { | 
| 102 | 0 |              throw new FormatException("formatting", RiceKeyConstants.ERROR_BIG_DECIMAL, obj.toString(), e); | 
| 103 | }  | |
| 104 | 0 |          catch (ClassCastException e) { | 
| 105 | 0 |              throw new FormatException("formatting", RiceKeyConstants.ERROR_BIG_DECIMAL, obj.toString(), e); | 
| 106 | 0 |          } | 
| 107 | ||
| 108 | 0 |          return string; | 
| 109 | }  | |
| 110 | }  |