Coverage Report - org.joda.money.format.MoneyAmountStyle
 
Classes in this File Line Coverage Branch Coverage Complexity
MoneyAmountStyle
98%
112/114
95%
88/92
3.24
 
 1  
 /*
 2  
  *  Copyright 2009-2013 Stephen Colebourne
 3  
  *
 4  
  *  Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
 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.joda.money.format;
 17  
 
 18  
 import java.io.Serializable;
 19  
 import java.lang.reflect.Method;
 20  
 import java.text.DecimalFormat;
 21  
 import java.text.DecimalFormatSymbols;
 22  
 import java.text.NumberFormat;
 23  
 import java.util.Locale;
 24  
 import java.util.concurrent.ConcurrentHashMap;
 25  
 import java.util.concurrent.ConcurrentMap;
 26  
 
 27  
 /**
 28  
  * Defines the style that the amount of a monetary value will be formatted with.
 29  
  * <p>
 30  
  * The style contains a number of fields that may be configured based on the locale:
 31  
  * <ul>
 32  
  * <li>character used for zero, which defined all the numbers from zero to nine
 33  
  * <li>character used for positive and negative symbols
 34  
  * <li>character used for the decimal point
 35  
  * <li>whether and how to group the amount
 36  
  * <li>character used for grouping, such as grouping thousands
 37  
  * <li>size for each group, such as 3 for thousands
 38  
  * <li>whether to always use a decimal point
 39  
  * </ul>
 40  
  * <p>
 41  
  * The style can be used in three basic ways.
 42  
  * <ul>
 43  
  * <li>set all the fields manually, resulting in the same amount style for all locales
 44  
  * <li>call {@link #localize} manually and optionally adjust to set as required
 45  
  * <li>leave the localized fields as {@code null} and let the locale in the
 46  
  *  formatter to determine the style
 47  
  * </ul>
 48  
  * <p>
 49  
  * This class is immutable and thread-safe.
 50  
  */
 51  
 public final class MoneyAmountStyle implements Serializable {
 52  
 
 53  
     /**
 54  
      * A style that uses ASCII digits/negative sign, the decimal point
 55  
      * and groups large amounts in 3's using a comma.
 56  
      * Forced decimal point is disabled.
 57  
      */
 58  1
     public static final MoneyAmountStyle ASCII_DECIMAL_POINT_GROUP3_COMMA =
 59  
         new MoneyAmountStyle('0', '+', '-', '.', GroupingStyle.FULL, ',', 3, false);
 60  
     /**
 61  
      * A style that uses ASCII digits/negative sign, the decimal point
 62  
      * and groups large amounts in 3's using a space.
 63  
      * Forced decimal point is disabled.
 64  
      */
 65  1
     public static final MoneyAmountStyle ASCII_DECIMAL_POINT_GROUP3_SPACE =
 66  
         new MoneyAmountStyle('0', '+', '-', '.', GroupingStyle.FULL, ' ', 3, false);
 67  
     /**
 68  
      * A style that uses ASCII digits/negative sign, the decimal point
 69  
      * and no grouping of large amounts.
 70  
      * Forced decimal point is disabled.
 71  
      */
 72  1
     public static final MoneyAmountStyle ASCII_DECIMAL_POINT_NO_GROUPING =
 73  
         new MoneyAmountStyle('0', '+', '-', '.', GroupingStyle.NONE, ',', 3, false);
 74  
     /**
 75  
      * A style that uses ASCII digits/negative sign, the decimal comma
 76  
      * and groups large amounts in 3's using a dot.
 77  
      * Forced decimal point is disabled.
 78  
      */
 79  1
     public static final MoneyAmountStyle ASCII_DECIMAL_COMMA_GROUP3_DOT =
 80  
         new MoneyAmountStyle('0', '+', '-', ',', GroupingStyle.FULL, '.', 3, false);
 81  
     /**
 82  
      * A style that uses ASCII digits/negative sign, the decimal comma
 83  
      * and groups large amounts in 3's using a space.
 84  
      * Forced decimal point is disabled.
 85  
      */
 86  1
     public static final MoneyAmountStyle ASCII_DECIMAL_COMMA_GROUP3_SPACE =
 87  
         new MoneyAmountStyle('0', '+', '-', ',', GroupingStyle.FULL, ' ', 3, false);
 88  
     /**
 89  
      * A style that uses ASCII digits/negative sign, the decimal point
 90  
      * and no grouping of large amounts.
 91  
      * Forced decimal point is disabled.
 92  
      */
 93  1
     public static final MoneyAmountStyle ASCII_DECIMAL_COMMA_NO_GROUPING =
 94  
         new MoneyAmountStyle('0', '+', '-', ',', GroupingStyle.NONE, '.', 3, false);
 95  
     /**
 96  
      * A style that will be filled in with localized values using the locale of the formatter.
 97  
      * Grouping is enabled. Forced decimal point is disabled.
 98  
      */
 99  1
     public static final MoneyAmountStyle LOCALIZED_GROUPING =
 100  
         new MoneyAmountStyle(-1, -1, -1, -1, GroupingStyle.FULL, -1, -1, false);
 101  
     /**
 102  
      * A style that will be filled in with localized values using the locale of the formatter.
 103  
      * Grouping is disabled. Forced decimal point is disabled.
 104  
      */
 105  1
     public static final MoneyAmountStyle LOCALIZED_NO_GROUPING =
 106  
         new MoneyAmountStyle(-1, -1, -1, -1, GroupingStyle.NONE, -1, -1, false);
 107  
     /**
 108  
      * Cache of localized styles.
 109  
      */
 110  1
     private static final ConcurrentMap<Locale, MoneyAmountStyle> LOCALIZED_CACHE = new ConcurrentHashMap<Locale, MoneyAmountStyle>();
 111  
     /**
 112  
      * Serialization version.
 113  
      */
 114  
     private static final long serialVersionUID = 1L;
 115  
 
 116  
     /**
 117  
      * The character defining zero, and thus the numbers zero to nine.
 118  
      */
 119  
     private final int zeroCharacter;
 120  
     /**
 121  
      * The character representing the positive sign.
 122  
      */
 123  
     private final int positiveCharacter;
 124  
     /**
 125  
      * The prefix string when the amount is negative.
 126  
      */
 127  
     private final int negativeCharacter;
 128  
     /**
 129  
      * The character used for the decimal point.
 130  
      */
 131  
     private final int decimalPointCharacter;
 132  
     /**
 133  
      * Whether to group or not.
 134  
      */
 135  
     private final GroupingStyle groupingStyle;
 136  
     /**
 137  
      * The character used for grouping.
 138  
      */
 139  
     private final int groupingCharacter;
 140  
     /**
 141  
      * The size of each group.
 142  
      */
 143  
     private final int groupingSize;
 144  
     /**
 145  
      * Whether to always require the decimal point to be visible.
 146  
      */
 147  
     private final boolean forceDecimalPoint;
 148  
 
 149  
     //-----------------------------------------------------------------------
 150  
     /**
 151  
      * Gets a localized style.
 152  
      * <p>
 153  
      * This creates a localized style for the specified locale.
 154  
      * Grouping will be enabled, forced decimal point will be disabled.
 155  
      *
 156  
      * @param locale  the locale to use, not null
 157  
      * @return the new instance, never null
 158  
      */
 159  
     public static MoneyAmountStyle of(Locale locale) {
 160  2
         return getLocalizedStyle(locale);
 161  
     }
 162  
 
 163  
     //-----------------------------------------------------------------------
 164  
     /**
 165  
      * Constructor, creating a new monetary instance.
 166  
      * 
 167  
      * @param zeroCharacter  the zero character
 168  
      * @param negativeCharacter  the negative sign
 169  
      * @param decimalPointCharacter  the decimal point character
 170  
      * @param groupingStyle  the grouping style, not null
 171  
      * @param groupingCharacter  the grouping character
 172  
      * @param groupingSize  the grouping size
 173  
      * @param forceDecimalPoint  whether to always use the decimal point character
 174  
      * @param postiveCharacter  the positive sign
 175  
      */
 176  
     private MoneyAmountStyle(
 177  
                 int zeroCharacter,
 178  
                 int positiveCharacter, int negativeCharacter,
 179  
                 int decimalPointCharacter, GroupingStyle groupingStyle,
 180  367
                 int groupingCharacter, int groupingSize, boolean forceDecimalPoint) {
 181  367
         this.zeroCharacter = zeroCharacter;
 182  367
         this.positiveCharacter = positiveCharacter;
 183  367
         this.negativeCharacter = negativeCharacter;
 184  367
         this.decimalPointCharacter = decimalPointCharacter;
 185  367
         this.groupingStyle = groupingStyle;
 186  367
         this.groupingCharacter = groupingCharacter;
 187  367
         this.groupingSize = groupingSize;
 188  367
         this.forceDecimalPoint = forceDecimalPoint;
 189  367
     }
 190  
 
 191  
     //-----------------------------------------------------------------------
 192  
     /**
 193  
      * Returns a {@code MoneyAmountStyle} instance configured for the specified locale.
 194  
      * <p>
 195  
      * This method will return a new instance where each field that was defined
 196  
      * to be localized (by being set to {@code null}) is filled in.
 197  
      * If this instance is fully defined (with all fields non-null), then this
 198  
      * method has no effect. Once this method is called, no method will return null.
 199  
      * <p>
 200  
      * The settings for the locale are pulled from {@link DecimalFormatSymbols} and
 201  
      * {@link DecimalFormat}.
 202  
      * 
 203  
      * @param locale  the locale to use, not null
 204  
      * @return the new instance for chaining, never null
 205  
      */
 206  
     public MoneyAmountStyle localize(Locale locale) {
 207  79
         MoneyFormatter.checkNotNull(locale, "Locale must not be null");
 208  79
         MoneyAmountStyle result = this;
 209  79
         MoneyAmountStyle protoStyle = null;
 210  79
         if (zeroCharacter < 0) {
 211  50
             protoStyle = getLocalizedStyle(locale);
 212  50
             result = result.withZeroCharacter(protoStyle.getZeroCharacter());
 213  
         }
 214  79
         if (positiveCharacter < 0) {
 215  51
             protoStyle = getLocalizedStyle(locale);
 216  51
             result = result.withPositiveSignCharacter(protoStyle.getPositiveSignCharacter());
 217  
         }
 218  79
         if (negativeCharacter < 0) {
 219  51
             protoStyle = getLocalizedStyle(locale);
 220  51
             result = result.withNegativeSignCharacter(protoStyle.getNegativeSignCharacter());
 221  
         }
 222  79
         if (decimalPointCharacter < 0) {
 223  50
             protoStyle = (protoStyle == null ? getLocalizedStyle(locale) : protoStyle);
 224  50
             result = result.withDecimalPointCharacter(protoStyle.getDecimalPointCharacter());
 225  
         }
 226  79
         if (groupingCharacter < 0) {
 227  51
             protoStyle = (protoStyle == null ? getLocalizedStyle(locale) : protoStyle);
 228  51
             result = result.withGroupingCharacter(protoStyle.getGroupingCharacter());
 229  
         }
 230  79
         if (groupingSize < 0) {
 231  52
             protoStyle = (protoStyle == null ? getLocalizedStyle(locale) : protoStyle);
 232  52
             result = result.withGroupingSize(protoStyle.getGroupingSize());
 233  
         }
 234  79
         return result;
 235  
     }
 236  
 
 237  
     //-----------------------------------------------------------------------
 238  
     /**
 239  
      * Gets the prototype localized style for the given locale.
 240  
      * <p>
 241  
      * This uses {@link DecimalFormatSymbols} and {@link NumberFormat}.
 242  
      * <p>
 243  
      * If JDK 6 or newer is being used, {@code DecimalFormatSymbols.getInstance(locale)}
 244  
      * will be used in order to allow the use of locales defined as extensions.
 245  
      * Otherwise, {@code new DecimalFormatSymbols(locale)} will be used.
 246  
      * 
 247  
      * @param locale  the {@link Locale} used to get the correct {@link DecimalFormatSymbols}
 248  
      * @return the symbols, never null
 249  
      */
 250  
     private static MoneyAmountStyle getLocalizedStyle(Locale locale) {
 251  154
         MoneyAmountStyle protoStyle = LOCALIZED_CACHE.get(locale);
 252  154
         if (protoStyle == null) {
 253  
             DecimalFormatSymbols symbols;
 254  
             try {
 255  4
                 Method method = DecimalFormatSymbols.class.getMethod("getInstance", new Class[] {Locale.class});
 256  4
                 symbols = (DecimalFormatSymbols) method.invoke(null, new Object[] {locale});  // handle JDK 6
 257  0
             } catch (Exception ex) {
 258  0
                 symbols = new DecimalFormatSymbols(locale);  // handle JDK 5
 259  4
             }
 260  4
             NumberFormat format = NumberFormat.getCurrencyInstance(locale);
 261  4
             int size = (format instanceof DecimalFormat ? ((DecimalFormat) format).getGroupingSize() : 3);
 262  4
             protoStyle = new MoneyAmountStyle(
 263  
                     symbols.getZeroDigit(),
 264  
                     '+', symbols.getMinusSign(),
 265  
                     symbols.getMonetaryDecimalSeparator(),
 266  
                     GroupingStyle.FULL, symbols.getGroupingSeparator(), size, false);
 267  4
             LOCALIZED_CACHE.putIfAbsent(locale, protoStyle);
 268  
         }
 269  154
         return protoStyle;
 270  
     }
 271  
 
 272  
     //-----------------------------------------------------------------------
 273  
     /**
 274  
      * Gets the character used for zero, and defining the characters zero to nine.
 275  
      * <p>
 276  
      * The UTF-8 standard supports a number of different numeric scripts.
 277  
      * Each script has the characters in order from zero to nine.
 278  
      * This method returns the zero character, which therefore also defines one to nine.
 279  
      * 
 280  
      * @return the zero character, null if to be determined by locale
 281  
      */
 282  
     public Character getZeroCharacter() {
 283  475
         return zeroCharacter < 0 ? null : (char) zeroCharacter;
 284  
     }
 285  
 
 286  
     /**
 287  
      * Returns a copy of this style with the specified zero character.
 288  
      * <p>
 289  
      * The UTF-8 standard supports a number of different numeric scripts.
 290  
      * Each script has the characters in order from zero to nine.
 291  
      * This method sets the zero character, which therefore also defines one to nine.
 292  
      * <p>
 293  
      * For English, this is a '0'. Some other scripts use different characters
 294  
      * for the numbers zero to nine.
 295  
      * 
 296  
      * @param zeroCharacter  the zero character, null if to be determined by locale
 297  
      * @return the new instance for chaining, never null
 298  
      */
 299  
     public MoneyAmountStyle withZeroCharacter(Character zeroCharacter) {
 300  60
         int zeroVal = (zeroCharacter == null ? -1 : zeroCharacter);
 301  60
         if (zeroVal == this.zeroCharacter) {
 302  2
             return this;
 303  
         }
 304  58
         return new MoneyAmountStyle(
 305  
                 zeroVal,
 306  
                 positiveCharacter, negativeCharacter,
 307  
                 decimalPointCharacter, groupingStyle,
 308  
                 groupingCharacter, groupingSize, forceDecimalPoint);
 309  
     }
 310  
 
 311  
     //-----------------------------------------------------------------------
 312  
     /**
 313  
      * Gets the character used for the positive sign character.
 314  
      * <p>
 315  
      * The standard ASCII symbol is '+'.
 316  
      * 
 317  
      * @return the format for positive amounts, null if to be determined by locale
 318  
      */
 319  
     public Character getPositiveSignCharacter() {
 320  108
         return positiveCharacter < 0 ? null : (char) positiveCharacter;
 321  
     }
 322  
 
 323  
     /**
 324  
      * Returns a copy of this style with the specified positive sign character.
 325  
      * <p>
 326  
      * The standard ASCII symbol is '+'.
 327  
      * 
 328  
      * @param positiveCharacter  the positive character, null if to be determined by locale
 329  
      * @return the new instance for chaining, never null
 330  
      */
 331  
     public MoneyAmountStyle withPositiveSignCharacter(Character positiveCharacter) {
 332  58
         int positiveVal = (positiveCharacter == null ? -1 : positiveCharacter);
 333  58
         if (positiveVal == this.positiveCharacter) {
 334  2
             return this;
 335  
         }
 336  56
         return new MoneyAmountStyle(
 337  
                 zeroCharacter,
 338  
                 positiveVal, negativeCharacter,
 339  
                 decimalPointCharacter, groupingStyle,
 340  
                 groupingCharacter, groupingSize, forceDecimalPoint);
 341  
     }
 342  
 
 343  
     //-----------------------------------------------------------------------
 344  
     /**
 345  
      * Gets the character used for the negative sign character.
 346  
      * <p>
 347  
      * The standard ASCII symbol is '-'.
 348  
      * 
 349  
      * @return the format for negative amounts, null if to be determined by locale
 350  
      */
 351  
     public Character getNegativeSignCharacter() {
 352  110
         return negativeCharacter < 0 ? null : (char) negativeCharacter;
 353  
     }
 354  
 
 355  
     /**
 356  
      * Returns a copy of this style with the specified negative sign character.
 357  
      * <p>
 358  
      * The standard ASCII symbol is '-'.
 359  
      * 
 360  
      * @param negativeCharacter  the negative character, null if to be determined by locale
 361  
      * @return the new instance for chaining, never null
 362  
      */
 363  
     public MoneyAmountStyle withNegativeSignCharacter(Character negativeCharacter) {
 364  58
         int negativeVal = (negativeCharacter == null ? -1 : negativeCharacter);
 365  58
         if (negativeVal == this.negativeCharacter) {
 366  2
             return this;
 367  
         }
 368  56
         return new MoneyAmountStyle(
 369  
                 zeroCharacter,
 370  
                 positiveCharacter, negativeVal,
 371  
                 decimalPointCharacter, groupingStyle,
 372  
                 groupingCharacter, groupingSize, forceDecimalPoint);
 373  
     }
 374  
 
 375  
     //-----------------------------------------------------------------------
 376  
     /**
 377  
      * Gets the character used for the decimal point.
 378  
      * 
 379  
      * @return the decimal point character, null if to be determined by locale
 380  
      */
 381  
     public Character getDecimalPointCharacter() {
 382  172
         return decimalPointCharacter < 0 ? null : (char) decimalPointCharacter;
 383  
     }
 384  
 
 385  
     /**
 386  
      * Returns a copy of this style with the specified decimal point character.
 387  
      * <p>
 388  
      * For English, this is a dot.
 389  
      * 
 390  
      * @param decimalPointCharacter  the decimal point character, null if to be determined by locale
 391  
      * @return the new instance for chaining, never null
 392  
      */
 393  
     public MoneyAmountStyle withDecimalPointCharacter(Character decimalPointCharacter) {
 394  58
         int dpVal = (decimalPointCharacter == null ? -1 : decimalPointCharacter);
 395  58
         if (dpVal == this.decimalPointCharacter) {
 396  2
             return this;
 397  
         }
 398  56
         return new MoneyAmountStyle(
 399  
                 zeroCharacter,
 400  
                 positiveCharacter, negativeCharacter,
 401  
                 dpVal, groupingStyle,
 402  
                 groupingCharacter, groupingSize, forceDecimalPoint);
 403  
     }
 404  
 
 405  
     //-----------------------------------------------------------------------
 406  
     /**
 407  
      * Gets the character used to separate groups, typically thousands.
 408  
      * 
 409  
      * @return the grouping character, null if to be determined by locale
 410  
      */
 411  
     public Character getGroupingCharacter() {
 412  135
         return groupingCharacter < 0 ? null : (char) groupingCharacter;
 413  
     }
 414  
 
 415  
     /**
 416  
      * Returns a copy of this style with the specified grouping character.
 417  
      * <p>
 418  
      * For English, this is a comma.
 419  
      * 
 420  
      * @param groupingCharacter  the grouping character, null if to be determined by locale
 421  
      * @return the new instance for chaining, never null
 422  
      */
 423  
     public MoneyAmountStyle withGroupingCharacter(Character groupingCharacter) {
 424  58
         int groupingVal = (groupingCharacter == null ? -1 : groupingCharacter);
 425  58
         if (groupingVal == this.groupingCharacter) {
 426  2
             return this;
 427  
         }
 428  56
         return new MoneyAmountStyle(
 429  
                 zeroCharacter,
 430  
                 positiveCharacter, negativeCharacter,
 431  
                 decimalPointCharacter, groupingStyle,
 432  
                 groupingVal, groupingSize, forceDecimalPoint);
 433  
     }
 434  
 
 435  
     //-----------------------------------------------------------------------
 436  
     /**
 437  
      * Gets the size of each group, typically 3 for thousands.
 438  
      * 
 439  
      * @return the size of each group, null if to be determined by locale
 440  
      */
 441  
     public Integer getGroupingSize() {
 442  102
         return groupingSize < 0 ? null : groupingSize;
 443  
     }
 444  
 
 445  
     /**
 446  
      * Returns a copy of this style with the specified grouping size.
 447  
      * 
 448  
      * @param groupingSize  the size of each group, such as 3 for thousands,
 449  
      *          not zero or negative, null if to be determined by locale
 450  
      * @return the new instance for chaining, never null
 451  
      * @throws IllegalArgumentException if the grouping size is zero or less
 452  
      */
 453  
     public MoneyAmountStyle withGroupingSize(Integer groupingSize) {
 454  59
         int sizeVal = (groupingSize == null ? -1 : groupingSize);
 455  59
         if (groupingSize != null && sizeVal <= 0) {
 456  1
             throw new IllegalArgumentException("Grouping size must be greater than zero");
 457  
         }
 458  58
         if (sizeVal == this.groupingSize) {
 459  2
             return this;
 460  
         }
 461  56
         return new MoneyAmountStyle(
 462  
                 zeroCharacter,
 463  
                 positiveCharacter, negativeCharacter,
 464  
                 decimalPointCharacter, groupingStyle,
 465  
                 groupingCharacter, sizeVal, forceDecimalPoint);
 466  
     }
 467  
 
 468  
     //-----------------------------------------------------------------------
 469  
     /**
 470  
      * Gets whether to use the grouping separator, typically for thousands.
 471  
      * 
 472  
      * @return whether to use the grouping separator
 473  
      * @deprecated Use getGroupingStyle()
 474  
      */
 475  
     @Deprecated
 476  
     public boolean isGrouping() {
 477  4
         return getGroupingStyle() == GroupingStyle.FULL;
 478  
     }
 479  
 
 480  
     /**
 481  
      * Returns a copy of this style with the specified grouping setting.
 482  
      * 
 483  
      * @param grouping  true to use the grouping separator, false to not use it
 484  
      * @return the new instance for chaining, never null
 485  
      * @deprecated Use withGroupingStyle(GroupingStyle.FULL)
 486  
      */
 487  
     @Deprecated
 488  
     public MoneyAmountStyle withGrouping(boolean grouping) {
 489  2
         return withGroupingStyle(grouping ? GroupingStyle.FULL : GroupingStyle.NONE);
 490  
     }
 491  
 
 492  
     //-----------------------------------------------------------------------
 493  
     /**
 494  
      * Gets the style of grouping required.
 495  
      * 
 496  
      * @return the grouping style, not null
 497  
      */
 498  
     public GroupingStyle getGroupingStyle() {
 499  90
         return groupingStyle;
 500  
     }
 501  
 
 502  
     /**
 503  
      * Returns a copy of this style with the specified grouping setting.
 504  
      * 
 505  
      * @param groupingStyle  the grouping style, not null
 506  
      * @return the new instance for chaining, never null
 507  
      */
 508  
     public MoneyAmountStyle withGroupingStyle(GroupingStyle groupingStyle) {
 509  9
         MoneyFormatter.checkNotNull(groupingStyle, "groupingStyle");
 510  9
         if (this.groupingStyle == groupingStyle) {
 511  2
             return this;
 512  
         }
 513  7
         return new MoneyAmountStyle(
 514  
                 zeroCharacter,
 515  
                 positiveCharacter, negativeCharacter,
 516  
                 decimalPointCharacter, groupingStyle,
 517  
                 groupingCharacter, groupingSize, forceDecimalPoint);
 518  
     }
 519  
 
 520  
     //-----------------------------------------------------------------------
 521  
     /**
 522  
      * Gets whether to always use the decimal point, even if there is no fraction.
 523  
      * 
 524  
      * @return whether to force the decimal point on output
 525  
      */
 526  
     public boolean isForcedDecimalPoint() {
 527  28
         return forceDecimalPoint;
 528  
     }
 529  
 
 530  
     /**
 531  
      * Returns a copy of this style with the specified decimal point setting.
 532  
      * 
 533  
      * @param forceDecimalPoint  true to force the use of the decimal point, false to use it if required
 534  
      * @return the new instance for chaining, never null
 535  
      */
 536  
     public MoneyAmountStyle withForcedDecimalPoint(boolean forceDecimalPoint) {
 537  11
         if (this.forceDecimalPoint == forceDecimalPoint) {
 538  1
             return this;
 539  
         }
 540  10
         return new MoneyAmountStyle(
 541  
                 zeroCharacter,
 542  
                 positiveCharacter, negativeCharacter,
 543  
                 decimalPointCharacter, groupingStyle,
 544  
                 groupingCharacter, groupingSize, forceDecimalPoint);
 545  
     }
 546  
 
 547  
     //-----------------------------------------------------------------------
 548  
     /**
 549  
      * Compares this style with another.
 550  
      * 
 551  
      * @param other  the other style, null returns false
 552  
      * @return true if equal
 553  
      */
 554  
     @Override
 555  
     public boolean equals(Object other) {
 556  37
         if (other == this) {
 557  1
             return true;
 558  
         }
 559  36
         if (other instanceof MoneyAmountStyle == false) {
 560  2
             return false;
 561  
         }
 562  34
         MoneyAmountStyle otherStyle = (MoneyAmountStyle) other;
 563  34
         return (zeroCharacter == otherStyle.zeroCharacter) &&
 564  
                 (positiveCharacter == otherStyle.positiveCharacter) &&
 565  
                 (negativeCharacter == otherStyle.negativeCharacter) &&
 566  
                 (decimalPointCharacter == otherStyle.decimalPointCharacter) &&
 567  
                 (groupingStyle == otherStyle.groupingStyle) &&
 568  
                 (groupingCharacter == otherStyle.groupingCharacter) &&
 569  
                 (groupingSize == otherStyle.groupingSize) &&
 570  
                 (forceDecimalPoint == otherStyle.forceDecimalPoint);
 571  
     }
 572  
 
 573  
     /**
 574  
      * A suitable hash code.
 575  
      * 
 576  
      * @return a hash code
 577  
      */
 578  
     @Override
 579  
     public int hashCode() {
 580  18
         int hash = 13;
 581  18
         hash += zeroCharacter * 17;
 582  18
         hash += positiveCharacter * 17;
 583  18
         hash += negativeCharacter * 17;
 584  18
         hash += decimalPointCharacter * 17;
 585  18
         hash += groupingStyle.hashCode() * 17;
 586  18
         hash += groupingCharacter * 17;
 587  18
         hash += groupingSize * 17;
 588  18
         hash += (forceDecimalPoint ? 2 : 4);
 589  18
         return hash;
 590  
     }
 591  
 
 592  
     //-----------------------------------------------------------------------
 593  
     /**
 594  
      * Gets a string summary of the style.
 595  
      * 
 596  
      * @return a string summarising the style, never null
 597  
      */
 598  
     @Override
 599  
     public String toString() {
 600  1
         return "MoneyAmountStyle['" + getZeroCharacter() + "','" + getPositiveSignCharacter() + "','" +
 601  
             getNegativeSignCharacter() + "','" + getDecimalPointCharacter() + "','" +
 602  
             getGroupingStyle() + "," + getGroupingCharacter() + "','" + getGroupingSize() + "'," +
 603  
             isForcedDecimalPoint() + "]";
 604  
     }
 605  
 
 606  
 }