From 712460af2bc9e27e516bad7e48fc79966a44adca Mon Sep 17 00:00:00 2001 From: Shane Carr Date: Thu, 28 Sep 2017 23:26:57 +0000 Subject: [PATCH] ICU-13177 Fixing ICU4J warnings in DecimalFormatProperties and CompactNotation. Reformatting DecimalFormatProperties.java. X-SVN-Rev: 40511 --- .../impl/number/DecimalFormatProperties.java | 2644 +++++++++-------- .../com/ibm/icu/number/CompactNotation.java | 1 + 2 files changed, 1341 insertions(+), 1304 deletions(-) diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalFormatProperties.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalFormatProperties.java index 3e8c8e594d..26859abe16 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalFormatProperties.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/DecimalFormatProperties.java @@ -26,1331 +26,1367 @@ import com.ibm.icu.util.Currency.CurrencyUsage; public class DecimalFormatProperties implements Cloneable, Serializable { - private static final DecimalFormatProperties DEFAULT = new DecimalFormatProperties(); + private static final DecimalFormatProperties DEFAULT = new DecimalFormatProperties(); - /** Auto-generated. */ - private static final long serialVersionUID = 4095518955889349243L; + /** Auto-generated. */ + private static final long serialVersionUID = 4095518955889349243L; - // The setters in this class should NOT have any side-effects or perform any validation. It is - // up to the consumer of the property bag to deal with property validation. + // The setters in this class should NOT have any side-effects or perform any validation. It is + // up to the consumer of the property bag to deal with property validation. - // The fields are all marked "transient" because custom serialization is being used. + // The fields are all marked "transient" because custom serialization is being used. - /*--------------------------------------------------------------------------------------------+/ - /| IMPORTANT! |/ - /| WHEN ADDING A NEW PROPERTY, add it here, in #_clear(), in #_copyFrom(), in #equals(), |/ - /| and in #_hashCode(). |/ - /| |/ - /| The unit test PropertiesTest will catch if you forget to add it to #clear(), #copyFrom(), |/ - /| or #equals(), but it will NOT catch if you forget to add it to #hashCode(). |/ - /+--------------------------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------------------------+/ + /| IMPORTANT! |/ + /| WHEN ADDING A NEW PROPERTY, add it here, in #_clear(), in #_copyFrom(), in #equals(), |/ + /| and in #_hashCode(). |/ + /| |/ + /| The unit test PropertiesTest will catch if you forget to add it to #clear(), #copyFrom(), |/ + /| or #equals(), but it will NOT catch if you forget to add it to #hashCode(). |/ + /+--------------------------------------------------------------------------------------------*/ - private transient Map> compactCustomData; - private transient CompactStyle compactStyle; - private transient Currency currency; - private transient CurrencyPluralInfo currencyPluralInfo; - private transient CurrencyUsage currencyUsage; - private transient boolean decimalPatternMatchRequired; - private transient boolean decimalSeparatorAlwaysShown; - private transient boolean exponentSignAlwaysShown; - private transient int formatWidth; - private transient int groupingSize; - private transient int magnitudeMultiplier; - private transient MathContext mathContext; - private transient int maximumFractionDigits; - private transient int maximumIntegerDigits; - private transient int maximumSignificantDigits; - private transient int minimumExponentDigits; - private transient int minimumFractionDigits; - private transient int minimumGroupingDigits; - private transient int minimumIntegerDigits; - private transient int minimumSignificantDigits; - private transient BigDecimal multiplier; - private transient String negativePrefix; - private transient String negativePrefixPattern; - private transient String negativeSuffix; - private transient String negativeSuffixPattern; - private transient PadPosition padPosition; - private transient String padString; - private transient boolean parseCaseSensitive; - private transient GroupingMode parseGroupingMode; - private transient boolean parseIntegerOnly; - private transient ParseMode parseMode; - private transient boolean parseNoExponent; - private transient boolean parseToBigDecimal; - private transient PluralRules pluralRules; - private transient String positivePrefix; - private transient String positivePrefixPattern; - private transient String positiveSuffix; - private transient String positiveSuffixPattern; - private transient BigDecimal roundingIncrement; - private transient RoundingMode roundingMode; - private transient int secondaryGroupingSize; - private transient boolean signAlwaysShown; + private transient Map> compactCustomData; + private transient CompactStyle compactStyle; + private transient Currency currency; + private transient CurrencyPluralInfo currencyPluralInfo; + private transient CurrencyUsage currencyUsage; + private transient boolean decimalPatternMatchRequired; + private transient boolean decimalSeparatorAlwaysShown; + private transient boolean exponentSignAlwaysShown; + private transient int formatWidth; + private transient int groupingSize; + private transient int magnitudeMultiplier; + private transient MathContext mathContext; + private transient int maximumFractionDigits; + private transient int maximumIntegerDigits; + private transient int maximumSignificantDigits; + private transient int minimumExponentDigits; + private transient int minimumFractionDigits; + private transient int minimumGroupingDigits; + private transient int minimumIntegerDigits; + private transient int minimumSignificantDigits; + private transient BigDecimal multiplier; + private transient String negativePrefix; + private transient String negativePrefixPattern; + private transient String negativeSuffix; + private transient String negativeSuffixPattern; + private transient PadPosition padPosition; + private transient String padString; + private transient boolean parseCaseSensitive; + private transient GroupingMode parseGroupingMode; + private transient boolean parseIntegerOnly; + private transient ParseMode parseMode; + private transient boolean parseNoExponent; + private transient boolean parseToBigDecimal; + private transient PluralRules pluralRules; + private transient String positivePrefix; + private transient String positivePrefixPattern; + private transient String positiveSuffix; + private transient String positiveSuffixPattern; + private transient BigDecimal roundingIncrement; + private transient RoundingMode roundingMode; + private transient int secondaryGroupingSize; + private transient boolean signAlwaysShown; - /*--------------------------------------------------------------------------------------------+/ - /| IMPORTANT! |/ - /| WHEN ADDING A NEW PROPERTY, add it here, in #_clear(), in #_copyFrom(), in #equals(), |/ - /| and in #_hashCode(). |/ - /| |/ - /| The unit test PropertiesTest will catch if you forget to add it to #clear(), #copyFrom(), |/ - /| or #equals(), but it will NOT catch if you forget to add it to #hashCode(). |/ - /+--------------------------------------------------------------------------------------------*/ + /*--------------------------------------------------------------------------------------------+/ + /| IMPORTANT! |/ + /| WHEN ADDING A NEW PROPERTY, add it here, in #_clear(), in #_copyFrom(), in #equals(), |/ + /| and in #_hashCode(). |/ + /| |/ + /| The unit test PropertiesTest will catch if you forget to add it to #clear(), #copyFrom(), |/ + /| or #equals(), but it will NOT catch if you forget to add it to #hashCode(). |/ + /+--------------------------------------------------------------------------------------------*/ - public DecimalFormatProperties() { - clear(); - } - - /** - * Sets all properties to their defaults (unset). - * - *

All integers default to -1 EXCEPT FOR MAGNITUDE MULTIPLIER which has a default of 0 (since - * negative numbers are important). - * - *

All booleans default to false. - * - *

All non-primitive types default to null. - * - * @return The property bag, for chaining. - */ - private DecimalFormatProperties _clear() { - compactCustomData = null; - compactStyle = null; - currency = null; - currencyPluralInfo = null; - currencyUsage = null; - decimalPatternMatchRequired = false; - decimalSeparatorAlwaysShown = false; - exponentSignAlwaysShown = false; - formatWidth = -1; - groupingSize = -1; - magnitudeMultiplier = 0; - mathContext = null; - maximumFractionDigits = -1; - maximumIntegerDigits = -1; - maximumSignificantDigits = -1; - minimumExponentDigits = -1; - minimumFractionDigits = -1; - minimumGroupingDigits = -1; - minimumIntegerDigits = -1; - minimumSignificantDigits = -1; - multiplier = null; - negativePrefix = null; - negativePrefixPattern = null; - negativeSuffix = null; - negativeSuffixPattern = null; - padPosition = null; - padString = null; - parseCaseSensitive = false; - parseGroupingMode = null; - parseIntegerOnly = false; - parseMode = null; - parseNoExponent = false; - parseToBigDecimal = false; - pluralRules = null; - positivePrefix = null; - positivePrefixPattern = null; - positiveSuffix = null; - positiveSuffixPattern = null; - roundingIncrement = null; - roundingMode = null; - secondaryGroupingSize = -1; - signAlwaysShown = false; - return this; - } - - private DecimalFormatProperties _copyFrom(DecimalFormatProperties other) { - compactCustomData = other.compactCustomData; - compactStyle = other.compactStyle; - currency = other.currency; - currencyPluralInfo = other.currencyPluralInfo; - currencyUsage = other.currencyUsage; - decimalPatternMatchRequired = other.decimalPatternMatchRequired; - decimalSeparatorAlwaysShown = other.decimalSeparatorAlwaysShown; - exponentSignAlwaysShown = other.exponentSignAlwaysShown; - formatWidth = other.formatWidth; - groupingSize = other.groupingSize; - magnitudeMultiplier = other.magnitudeMultiplier; - mathContext = other.mathContext; - maximumFractionDigits = other.maximumFractionDigits; - maximumIntegerDigits = other.maximumIntegerDigits; - maximumSignificantDigits = other.maximumSignificantDigits; - minimumExponentDigits = other.minimumExponentDigits; - minimumFractionDigits = other.minimumFractionDigits; - minimumGroupingDigits = other.minimumGroupingDigits; - minimumIntegerDigits = other.minimumIntegerDigits; - minimumSignificantDigits = other.minimumSignificantDigits; - multiplier = other.multiplier; - negativePrefix = other.negativePrefix; - negativePrefixPattern = other.negativePrefixPattern; - negativeSuffix = other.negativeSuffix; - negativeSuffixPattern = other.negativeSuffixPattern; - padPosition = other.padPosition; - padString = other.padString; - parseCaseSensitive = other.parseCaseSensitive; - parseGroupingMode = other.parseGroupingMode; - parseIntegerOnly = other.parseIntegerOnly; - parseMode = other.parseMode; - parseNoExponent = other.parseNoExponent; - parseToBigDecimal = other.parseToBigDecimal; - pluralRules = other.pluralRules; - positivePrefix = other.positivePrefix; - positivePrefixPattern = other.positivePrefixPattern; - positiveSuffix = other.positiveSuffix; - positiveSuffixPattern = other.positiveSuffixPattern; - roundingIncrement = other.roundingIncrement; - roundingMode = other.roundingMode; - secondaryGroupingSize = other.secondaryGroupingSize; - signAlwaysShown = other.signAlwaysShown; - return this; - } - - private boolean _equals(DecimalFormatProperties other) { - boolean eq = true; - eq = eq && _equalsHelper(compactCustomData, other.compactCustomData); - eq = eq && _equalsHelper(compactStyle, other.compactStyle); - eq = eq && _equalsHelper(currency, other.currency); - eq = eq && _equalsHelper(currencyPluralInfo, other.currencyPluralInfo); - eq = eq && _equalsHelper(currencyUsage, other.currencyUsage); - eq = eq && _equalsHelper(decimalPatternMatchRequired, other.decimalPatternMatchRequired); - eq = eq && _equalsHelper(decimalSeparatorAlwaysShown, other.decimalSeparatorAlwaysShown); - eq = eq && _equalsHelper(exponentSignAlwaysShown, other.exponentSignAlwaysShown); - eq = eq && _equalsHelper(formatWidth, other.formatWidth); - eq = eq && _equalsHelper(groupingSize, other.groupingSize); - eq = eq && _equalsHelper(magnitudeMultiplier, other.magnitudeMultiplier); - eq = eq && _equalsHelper(mathContext, other.mathContext); - eq = eq && _equalsHelper(maximumFractionDigits, other.maximumFractionDigits); - eq = eq && _equalsHelper(maximumIntegerDigits, other.maximumIntegerDigits); - eq = eq && _equalsHelper(maximumSignificantDigits, other.maximumSignificantDigits); - eq = eq && _equalsHelper(minimumExponentDigits, other.minimumExponentDigits); - eq = eq && _equalsHelper(minimumFractionDigits, other.minimumFractionDigits); - eq = eq && _equalsHelper(minimumGroupingDigits, other.minimumGroupingDigits); - eq = eq && _equalsHelper(minimumIntegerDigits, other.minimumIntegerDigits); - eq = eq && _equalsHelper(minimumSignificantDigits, other.minimumSignificantDigits); - eq = eq && _equalsHelper(multiplier, other.multiplier); - eq = eq && _equalsHelper(negativePrefix, other.negativePrefix); - eq = eq && _equalsHelper(negativePrefixPattern, other.negativePrefixPattern); - eq = eq && _equalsHelper(negativeSuffix, other.negativeSuffix); - eq = eq && _equalsHelper(negativeSuffixPattern, other.negativeSuffixPattern); - eq = eq && _equalsHelper(padPosition, other.padPosition); - eq = eq && _equalsHelper(padString, other.padString); - eq = eq && _equalsHelper(parseCaseSensitive, other.parseCaseSensitive); - eq = eq && _equalsHelper(parseGroupingMode, other.parseGroupingMode); - eq = eq && _equalsHelper(parseIntegerOnly, other.parseIntegerOnly); - eq = eq && _equalsHelper(parseMode, other.parseMode); - eq = eq && _equalsHelper(parseNoExponent, other.parseNoExponent); - eq = eq && _equalsHelper(parseToBigDecimal, other.parseToBigDecimal); - eq = eq && _equalsHelper(pluralRules, other.pluralRules); - eq = eq && _equalsHelper(positivePrefix, other.positivePrefix); - eq = eq && _equalsHelper(positivePrefixPattern, other.positivePrefixPattern); - eq = eq && _equalsHelper(positiveSuffix, other.positiveSuffix); - eq = eq && _equalsHelper(positiveSuffixPattern, other.positiveSuffixPattern); - eq = eq && _equalsHelper(roundingIncrement, other.roundingIncrement); - eq = eq && _equalsHelper(roundingMode, other.roundingMode); - eq = eq && _equalsHelper(secondaryGroupingSize, other.secondaryGroupingSize); - eq = eq && _equalsHelper(signAlwaysShown, other.signAlwaysShown); - return eq; - } - - private boolean _equalsHelper(boolean mine, boolean theirs) { - return mine == theirs; - } - - private boolean _equalsHelper(int mine, int theirs) { - return mine == theirs; - } - - private boolean _equalsHelper(Object mine, Object theirs) { - if (mine == theirs) return true; - if (mine == null) return false; - return mine.equals(theirs); - } - - private int _hashCode() { - int hashCode = 0; - hashCode ^= _hashCodeHelper(compactCustomData); - hashCode ^= _hashCodeHelper(compactStyle); - hashCode ^= _hashCodeHelper(currency); - hashCode ^= _hashCodeHelper(currencyPluralInfo); - hashCode ^= _hashCodeHelper(currencyUsage); - hashCode ^= _hashCodeHelper(decimalPatternMatchRequired); - hashCode ^= _hashCodeHelper(decimalSeparatorAlwaysShown); - hashCode ^= _hashCodeHelper(exponentSignAlwaysShown); - hashCode ^= _hashCodeHelper(formatWidth); - hashCode ^= _hashCodeHelper(groupingSize); - hashCode ^= _hashCodeHelper(magnitudeMultiplier); - hashCode ^= _hashCodeHelper(mathContext); - hashCode ^= _hashCodeHelper(maximumFractionDigits); - hashCode ^= _hashCodeHelper(maximumIntegerDigits); - hashCode ^= _hashCodeHelper(maximumSignificantDigits); - hashCode ^= _hashCodeHelper(minimumExponentDigits); - hashCode ^= _hashCodeHelper(minimumFractionDigits); - hashCode ^= _hashCodeHelper(minimumGroupingDigits); - hashCode ^= _hashCodeHelper(minimumIntegerDigits); - hashCode ^= _hashCodeHelper(minimumSignificantDigits); - hashCode ^= _hashCodeHelper(multiplier); - hashCode ^= _hashCodeHelper(negativePrefix); - hashCode ^= _hashCodeHelper(negativePrefixPattern); - hashCode ^= _hashCodeHelper(negativeSuffix); - hashCode ^= _hashCodeHelper(negativeSuffixPattern); - hashCode ^= _hashCodeHelper(padPosition); - hashCode ^= _hashCodeHelper(padString); - hashCode ^= _hashCodeHelper(parseCaseSensitive); - hashCode ^= _hashCodeHelper(parseGroupingMode); - hashCode ^= _hashCodeHelper(parseIntegerOnly); - hashCode ^= _hashCodeHelper(parseMode); - hashCode ^= _hashCodeHelper(parseNoExponent); - hashCode ^= _hashCodeHelper(parseToBigDecimal); - hashCode ^= _hashCodeHelper(pluralRules); - hashCode ^= _hashCodeHelper(positivePrefix); - hashCode ^= _hashCodeHelper(positivePrefixPattern); - hashCode ^= _hashCodeHelper(positiveSuffix); - hashCode ^= _hashCodeHelper(positiveSuffixPattern); - hashCode ^= _hashCodeHelper(roundingIncrement); - hashCode ^= _hashCodeHelper(roundingMode); - hashCode ^= _hashCodeHelper(secondaryGroupingSize); - hashCode ^= _hashCodeHelper(signAlwaysShown); - return hashCode; - } - - private int _hashCodeHelper(boolean value) { - return value ? 1 : 0; - } - - private int _hashCodeHelper(int value) { - return value * 13; - } - - private int _hashCodeHelper(Object value) { - if (value == null) return 0; - return value.hashCode(); - } - - public DecimalFormatProperties clear() { - return _clear(); - } - - /** Creates and returns a shallow copy of the property bag. */ - @Override - public DecimalFormatProperties clone() { - // super.clone() returns a shallow copy. - try { - return (DecimalFormatProperties) super.clone(); - } catch (CloneNotSupportedException e) { - // Should never happen since super is Object - throw new UnsupportedOperationException(e); + public DecimalFormatProperties() { + clear(); } - } - /** - * Shallow-copies the properties from the given property bag into this property bag. - * - * @param other The property bag from which to copy and which will not be modified. - * @return The current property bag (the one modified by this operation), for chaining. - */ - public DecimalFormatProperties copyFrom(DecimalFormatProperties other) { - return _copyFrom(other); - } - - @Override - public boolean equals(Object other) { - if (other == null) return false; - if (this == other) return true; - if (!(other instanceof DecimalFormatProperties)) return false; - return _equals((DecimalFormatProperties) other); - } - - /// BEGIN GETTERS/SETTERS /// - - public Map> getCompactCustomData() { - return compactCustomData; - } - - public CompactStyle getCompactStyle() { - return compactStyle; - } - - public Currency getCurrency() { - return currency; - } - - public CurrencyPluralInfo getCurrencyPluralInfo() { - return currencyPluralInfo; - } - - public CurrencyUsage getCurrencyUsage() { - return currencyUsage; - } - - public boolean getDecimalPatternMatchRequired() { - return decimalPatternMatchRequired; - } - - public boolean getDecimalSeparatorAlwaysShown() { - return decimalSeparatorAlwaysShown; - } - - public boolean getExponentSignAlwaysShown() { - return exponentSignAlwaysShown; - } - - public int getFormatWidth() { - return formatWidth; - } - - public int getGroupingSize() { - return groupingSize; - } - - public int getMagnitudeMultiplier() { - return magnitudeMultiplier; - } - - public MathContext getMathContext() { - return mathContext; - } - - public int getMaximumFractionDigits() { - return maximumFractionDigits; - } - - public int getMaximumIntegerDigits() { - return maximumIntegerDigits; - } - - public int getMaximumSignificantDigits() { - return maximumSignificantDigits; - } - - public int getMinimumExponentDigits() { - return minimumExponentDigits; - } - - public int getMinimumFractionDigits() { - return minimumFractionDigits; - } - - public int getMinimumGroupingDigits() { - return minimumGroupingDigits; - } - - public int getMinimumIntegerDigits() { - return minimumIntegerDigits; - } - - public int getMinimumSignificantDigits() { - return minimumSignificantDigits; - } - - public BigDecimal getMultiplier() { - return multiplier; - } - - public String getNegativePrefix() { - return negativePrefix; - } - - public String getNegativePrefixPattern() { - return negativePrefixPattern; - } - - public String getNegativeSuffix() { - return negativeSuffix; - } - - public String getNegativeSuffixPattern() { - return negativeSuffixPattern; - } - - public PadPosition getPadPosition() { - return padPosition; - } - - public String getPadString() { - return padString; - } - - public boolean getParseCaseSensitive() { - return parseCaseSensitive; - } - - public GroupingMode getParseGroupingMode() { - return parseGroupingMode; - } - - public boolean getParseIntegerOnly() { - return parseIntegerOnly; - } - - public ParseMode getParseMode() { - return parseMode; - } - - public boolean getParseNoExponent() { - return parseNoExponent; - } - - public boolean getParseToBigDecimal() { - return parseToBigDecimal; - } - - public PluralRules getPluralRules() { - return pluralRules; - } - - public String getPositivePrefix() { - return positivePrefix; - } - - public String getPositivePrefixPattern() { - return positivePrefixPattern; - } - - public String getPositiveSuffix() { - return positiveSuffix; - } - - public String getPositiveSuffixPattern() { - return positiveSuffixPattern; - } - - public BigDecimal getRoundingIncrement() { - return roundingIncrement; - } - - public RoundingMode getRoundingMode() { - return roundingMode; - } - - public int getSecondaryGroupingSize() { - return secondaryGroupingSize; - } - - public boolean getSignAlwaysShown() { - return signAlwaysShown; - } - - @Override - public int hashCode() { - return _hashCode(); - } - - /** Custom serialization: re-create object from serialized properties. */ - private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { - readObjectImpl(ois); - } - - /* package-private */ void readObjectImpl(ObjectInputStream ois) throws IOException, ClassNotFoundException { - ois.defaultReadObject(); - - // Initialize to empty - clear(); - - // Extra int for possible future use - ois.readInt(); - - // 1) How many fields were serialized? - int count = ois.readInt(); - - // 2) Read each field by its name and value - for (int i = 0; i < count; i++) { - String name = (String) ois.readObject(); - Object value = ois.readObject(); - - // Get the field reference - Field field = null; - try { - field = DecimalFormatProperties.class.getDeclaredField(name); - } catch (NoSuchFieldException e) { - // The field name does not exist! Possibly corrupted serialization. Ignore this entry. - continue; - } catch (SecurityException e) { - // Should not happen - throw new AssertionError(e); - } - - // NOTE: If the type of a field were changed in the future, this would be the place to check: - // If the variable `value` is the old type, perform any conversions necessary. - - // Save value into the field - try { - field.set(this, value); - } catch (IllegalArgumentException e) { - // Should not happen - throw new AssertionError(e); - } catch (IllegalAccessException e) { - // Should not happen - throw new AssertionError(e); - } + /** + * Sets all properties to their defaults (unset). + * + *

+ * All integers default to -1 EXCEPT FOR MAGNITUDE MULTIPLIER which has a default of 0 (since negative numbers are + * important). + * + *

+ * All booleans default to false. + * + *

+ * All non-primitive types default to null. + * + * @return The property bag, for chaining. + */ + private DecimalFormatProperties _clear() { + compactCustomData = null; + compactStyle = null; + currency = null; + currencyPluralInfo = null; + currencyUsage = null; + decimalPatternMatchRequired = false; + decimalSeparatorAlwaysShown = false; + exponentSignAlwaysShown = false; + formatWidth = -1; + groupingSize = -1; + magnitudeMultiplier = 0; + mathContext = null; + maximumFractionDigits = -1; + maximumIntegerDigits = -1; + maximumSignificantDigits = -1; + minimumExponentDigits = -1; + minimumFractionDigits = -1; + minimumGroupingDigits = -1; + minimumIntegerDigits = -1; + minimumSignificantDigits = -1; + multiplier = null; + negativePrefix = null; + negativePrefixPattern = null; + negativeSuffix = null; + negativeSuffixPattern = null; + padPosition = null; + padString = null; + parseCaseSensitive = false; + parseGroupingMode = null; + parseIntegerOnly = false; + parseMode = null; + parseNoExponent = false; + parseToBigDecimal = false; + pluralRules = null; + positivePrefix = null; + positivePrefixPattern = null; + positiveSuffix = null; + positiveSuffixPattern = null; + roundingIncrement = null; + roundingMode = null; + secondaryGroupingSize = -1; + signAlwaysShown = false; + return this; } - } - /** - * Specifies custom data to be used instead of CLDR data when constructing a CompactDecimalFormat. - * The argument should be a map with the following structure: - * - *

-   * {
-   *   "1000": {
-   *     "one": "0 thousand",
-   *     "other": "0 thousand"
-   *   },
-   *   "10000": {
-   *     "one": "00 thousand",
-   *     "other": "00 thousand"
-   *   },
-   *   // ...
-   * }
-   * 
- * - * This API endpoint is used by the CLDR Survey Tool. - * - * @param compactCustomData A map with the above structure. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setCompactCustomData(Map> compactCustomData) { - // TODO: compactCustomData is not immutable. - this.compactCustomData = compactCustomData; - return this; - } - - /** - * Use compact decimal formatting with the specified {@link CompactStyle}. CompactStyle.SHORT - * produces output like "10K" in locale en-US, whereas CompactStyle.LONG produces output - * like "10 thousand" in that locale. - * - * @param compactStyle The style of prefixes/suffixes to append. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setCompactStyle(CompactStyle compactStyle) { - this.compactStyle = compactStyle; - return this; - } - - /** - * Use the specified currency to substitute currency placeholders ('¤') in the pattern string. - * - * @param currency The currency. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setCurrency(Currency currency) { - this.currency = currency; - return this; - } - - /** - * Use the specified {@link CurrencyPluralInfo} instance when formatting currency long names. - * - * @param currencyPluralInfo The currency plural info object. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setCurrencyPluralInfo(CurrencyPluralInfo currencyPluralInfo) { - // TODO: In order to maintain immutability, we have to perform a clone here. - // It would be better to just retire CurrencyPluralInfo entirely. - if (currencyPluralInfo != null) { - currencyPluralInfo = (CurrencyPluralInfo) currencyPluralInfo.clone(); + private DecimalFormatProperties _copyFrom(DecimalFormatProperties other) { + compactCustomData = other.compactCustomData; + compactStyle = other.compactStyle; + currency = other.currency; + currencyPluralInfo = other.currencyPluralInfo; + currencyUsage = other.currencyUsage; + decimalPatternMatchRequired = other.decimalPatternMatchRequired; + decimalSeparatorAlwaysShown = other.decimalSeparatorAlwaysShown; + exponentSignAlwaysShown = other.exponentSignAlwaysShown; + formatWidth = other.formatWidth; + groupingSize = other.groupingSize; + magnitudeMultiplier = other.magnitudeMultiplier; + mathContext = other.mathContext; + maximumFractionDigits = other.maximumFractionDigits; + maximumIntegerDigits = other.maximumIntegerDigits; + maximumSignificantDigits = other.maximumSignificantDigits; + minimumExponentDigits = other.minimumExponentDigits; + minimumFractionDigits = other.minimumFractionDigits; + minimumGroupingDigits = other.minimumGroupingDigits; + minimumIntegerDigits = other.minimumIntegerDigits; + minimumSignificantDigits = other.minimumSignificantDigits; + multiplier = other.multiplier; + negativePrefix = other.negativePrefix; + negativePrefixPattern = other.negativePrefixPattern; + negativeSuffix = other.negativeSuffix; + negativeSuffixPattern = other.negativeSuffixPattern; + padPosition = other.padPosition; + padString = other.padString; + parseCaseSensitive = other.parseCaseSensitive; + parseGroupingMode = other.parseGroupingMode; + parseIntegerOnly = other.parseIntegerOnly; + parseMode = other.parseMode; + parseNoExponent = other.parseNoExponent; + parseToBigDecimal = other.parseToBigDecimal; + pluralRules = other.pluralRules; + positivePrefix = other.positivePrefix; + positivePrefixPattern = other.positivePrefixPattern; + positiveSuffix = other.positiveSuffix; + positiveSuffixPattern = other.positiveSuffixPattern; + roundingIncrement = other.roundingIncrement; + roundingMode = other.roundingMode; + secondaryGroupingSize = other.secondaryGroupingSize; + signAlwaysShown = other.signAlwaysShown; + return this; } - this.currencyPluralInfo = currencyPluralInfo; - return this; - } - /** - * Use the specified {@link CurrencyUsage} instance, which provides default rounding rules for the - * currency in two styles, CurrencyUsage.CASH and CurrencyUsage.STANDARD. - * - *

The CurrencyUsage specified here will not be used unless there is a currency placeholder in - * the pattern. - * - * @param currencyUsage The currency usage. Defaults to CurrencyUsage.STANDARD. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setCurrencyUsage(CurrencyUsage currencyUsage) { - this.currencyUsage = currencyUsage; - return this; - } - - /** - * PARSING: Whether to require that the presence of decimal point matches the pattern. If a - * decimal point is not present, but the pattern contained a decimal point, parse will not - * succeed: null will be returned from parse(), and an error index will be set in the - * {@link ParsePosition}. - * - * @param decimalPatternMatchRequired true to set an error if decimal is not present - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setDecimalPatternMatchRequired(boolean decimalPatternMatchRequired) { - this.decimalPatternMatchRequired = decimalPatternMatchRequired; - return this; - } - - /** - * Sets whether to always show the decimal point, even if the number doesn't require one. For - * example, if always show decimal is true, the number 123 would be formatted as "123." in locale - * en-US. - * - * @param decimalSeparatorAlwaysShown Whether to show the decimal point when it is optional. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setDecimalSeparatorAlwaysShown(boolean alwaysShowDecimal) { - this.decimalSeparatorAlwaysShown = alwaysShowDecimal; - return this; - } - - /** - * Sets whether to show the plus sign in the exponent part of numbers with a zero or positive - * exponent. For example, the number "1200" with the pattern "0.0E0" would be formatted as - * "1.2E+3" instead of "1.2E3" in en-US. - * - * @param exponentSignAlwaysShown Whether to show the plus sign in positive exponents. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setExponentSignAlwaysShown(boolean exponentSignAlwaysShown) { - this.exponentSignAlwaysShown = exponentSignAlwaysShown; - return this; - } - - /** - * Sets the minimum width of the string output by the formatting pipeline. For example, if padding - * is enabled and paddingWidth is set to 6, formatting the number "3.14159" with the pattern - * "0.00" will result in "··3.14" if '·' is your padding string. - * - *

If the number is longer than your padding width, the number will display as if no padding - * width had been specified, which may result in strings longer than the padding width. - * - *

Width is counted in UTF-16 code units. - * - * @param formatWidth The output width. - * @return The property bag, for chaining. - * @see #setPadPosition - * @see #setPadString - */ - public DecimalFormatProperties setFormatWidth(int paddingWidth) { - this.formatWidth = paddingWidth; - return this; - } - - /** - * Sets the number of digits between grouping separators. For example, the en-US locale - * uses a grouping size of 3, so the number 1234567 would be formatted as "1,234,567". For locales - * whose grouping sizes vary with magnitude, see {@link #setSecondaryGroupingSize(int)}. - * - * @param groupingSize The primary grouping size. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setGroupingSize(int groupingSize) { - this.groupingSize = groupingSize; - return this; - } - - /** - * Multiply all numbers by this power of ten before formatting. Negative multipliers reduce the - * magnitude and make numbers smaller (closer to zero). - * - * @param magnitudeMultiplier The number of powers of ten to scale. - * @return The property bag, for chaining. - * @see #setMultiplier - */ - public DecimalFormatProperties setMagnitudeMultiplier(int magnitudeMultiplier) { - this.magnitudeMultiplier = magnitudeMultiplier; - return this; - } - - /** - * Sets the {@link MathContext} to be used during math and rounding operations. A MathContext - * encapsulates a RoundingMode and the number of significant digits in the output. - * - * @param mathContext The math context to use when rounding is required. - * @return The property bag, for chaining. - * @see MathContext - * @see #setRoundingMode - */ - public DecimalFormatProperties setMathContext(MathContext mathContext) { - this.mathContext = mathContext; - return this; - } - - /** - * Sets the maximum number of digits to display after the decimal point. If the number has fewer - * than this number of digits, the number will be rounded off using the rounding mode specified by - * {@link #setRoundingMode(RoundingMode)}. The pattern "#00.0#", for example, corresponds to 2 - * maximum fraction digits, and the number 456.789 would be formatted as "456.79" in locale - * en-US with the default rounding mode. Note that the number 456.999 would be formatted - * as "457.0" given the same configurations. - * - * @param maximumFractionDigits The maximum number of fraction digits to output. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setMaximumFractionDigits(int maximumFractionDigits) { - this.maximumFractionDigits = maximumFractionDigits; - return this; - } - - /** - * Sets the maximum number of digits to display before the decimal point. If the number has more - * than this number of digits, the extra digits will be truncated. For example, if maximum integer - * digits is 2, and you attempt to format the number 1970, you will get "70" in locale - * en-US. It is not possible to specify the maximum integer digits using a pattern - * string, except in the special case of a scientific format pattern. - * - * @param maximumIntegerDigits The maximum number of integer digits to output. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setMaximumIntegerDigits(int maximumIntegerDigits) { - this.maximumIntegerDigits = maximumIntegerDigits; - return this; - } - - /** - * Sets the maximum number of significant digits to display. The number of significant digits is - * equal to the number of digits counted from the leftmost nonzero digit through the rightmost - * nonzero digit; for example, the number "2010" has 3 significant digits. If the number has more - * significant digits than specified here, the extra significant digits will be rounded off using - * the rounding mode specified by {@link #setRoundingMode(RoundingMode)}. For example, if maximum - * significant digits is 3, the number 1234.56 will be formatted as "1230" in locale - * en-US with the default rounding mode. - * - *

If both maximum significant digits and maximum integer/fraction digits are set at the same - * time, the behavior is undefined. - * - *

The number of significant digits can be specified in a pattern string using the '@' - * character. For example, the pattern "@@#" corresponds to a minimum of 2 and a maximum of 3 - * significant digits. - * - * @param maximumSignificantDigits The maximum number of significant digits to display. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setMaximumSignificantDigits(int maximumSignificantDigits) { - this.maximumSignificantDigits = maximumSignificantDigits; - return this; - } - - /** - * Sets the minimum number of digits to display in the exponent. For example, the number "1200" - * with the pattern "0.0E00", which has 2 exponent digits, would be formatted as "1.2E03" in - * en-US. - * - * @param minimumExponentDigits The minimum number of digits to display in the exponent field. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setMinimumExponentDigits(int exponentDigits) { - this.minimumExponentDigits = exponentDigits; - return this; - } - - /** - * Sets the minimum number of digits to display after the decimal point. If the number has fewer - * than this number of digits, the number will be padded with zeros. The pattern "#00.0#", for - * example, corresponds to 1 minimum fraction digit, and the number 456 would be formatted as - * "456.0" in locale en-US. - * - * @param minimumFractionDigits The minimum number of fraction digits to output. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setMinimumFractionDigits(int minimumFractionDigits) { - this.minimumFractionDigits = minimumFractionDigits; - return this; - } - - /** - * Sets the minimum number of digits required to be beyond the first grouping separator in order - * to enable grouping. For example, if the minimum grouping digits is 2, then 1234 would be - * formatted as "1234" but 12345 would be formatted as "12,345" in en-US. Note that - * 1234567 would still be formatted as "1,234,567", not "1234,567". - * - * @param minimumGroupingDigits How many digits must appear before a grouping separator before - * enabling grouping. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setMinimumGroupingDigits(int minimumGroupingDigits) { - this.minimumGroupingDigits = minimumGroupingDigits; - return this; - } - - /** - * Sets the minimum number of digits to display before the decimal point. If the number has fewer - * than this number of digits, the number will be padded with zeros. The pattern "#00.0#", for - * example, corresponds to 2 minimum integer digits, and the number 5.3 would be formatted as - * "05.3" in locale en-US. - * - * @param minimumIntegerDigits The minimum number of integer digits to output. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setMinimumIntegerDigits(int minimumIntegerDigits) { - this.minimumIntegerDigits = minimumIntegerDigits; - return this; - } - - /** - * Sets the minimum number of significant digits to display. If, after rounding to the number of - * significant digits specified by {@link #setMaximumSignificantDigits}, the number of remaining - * significant digits is less than the minimum, the number will be padded with zeros. For example, - * if minimum significant digits is 3, the number 5.8 will be formatted as "5.80" in locale - * en-US. Note that minimum significant digits is relevant only when numbers have digits - * after the decimal point. - * - *

If both minimum significant digits and minimum integer/fraction digits are set at the same - * time, both values will be respected, and the one that results in the greater number of padding - * zeros will be used. For example, formatting the number 73 with 3 minimum significant digits and - * 2 minimum fraction digits will produce "73.00". - * - *

The number of significant digits can be specified in a pattern string using the '@' - * character. For example, the pattern "@@#" corresponds to a minimum of 2 and a maximum of 3 - * significant digits. - * - * @param minimumSignificantDigits The minimum number of significant digits to display. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setMinimumSignificantDigits(int minimumSignificantDigits) { - this.minimumSignificantDigits = minimumSignificantDigits; - return this; - } - - /** - * Multiply all numbers by this amount before formatting. - * - * @param multiplier The amount to multiply by. - * @return The property bag, for chaining. - * @see #setMagnitudeMultiplier - */ - public DecimalFormatProperties setMultiplier(BigDecimal multiplier) { - this.multiplier = multiplier; - return this; - } - - /** - * Sets the prefix to prepend to negative numbers. The prefix will be interpreted literally. For - * example, if you set a negative prefix of n, then the number -123 will be formatted - * as "n123" in the locale en-US. Note that if the negative prefix is left unset, the - * locale's minus sign is used. - * - *

For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}. - * - * @param negativePrefix The CharSequence to prepend to negative numbers. - * @return The property bag, for chaining. - * @see PositiveNegativeAffixFormat - * @see #setNegativePrefixPattern - */ - public DecimalFormatProperties setNegativePrefix(String negativePrefix) { - this.negativePrefix = negativePrefix; - return this; - } - - /** - * Sets the prefix to prepend to negative numbers. Locale-specific symbols will be substituted - * into the string according to Unicode Technical Standard #35 (LDML). - * - *

For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}. - * - * @param negativePrefixPattern The CharSequence to prepend to negative numbers after locale - * symbol substitutions take place. - * @return The property bag, for chaining. - * @see PositiveNegativeAffixFormat - * @see #setNegativePrefix - */ - public DecimalFormatProperties setNegativePrefixPattern(String negativePrefixPattern) { - this.negativePrefixPattern = negativePrefixPattern; - return this; - } - - /** - * Sets the suffix to append to negative numbers. The suffix will be interpreted literally. For - * example, if you set a suffix prefix of n, then the number -123 will be formatted - * as "-123n" in the locale en-US. Note that the minus sign is prepended by default - * unless otherwise specified in either the pattern string or in one of the {@link - * #setNegativePrefix} methods. - * - *

For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}. - * - * @param negativeSuffix The CharSequence to append to negative numbers. - * @return The property bag, for chaining. - * @see PositiveNegativeAffixFormat - * @see #setNegativeSuffixPattern - */ - public DecimalFormatProperties setNegativeSuffix(String negativeSuffix) { - this.negativeSuffix = negativeSuffix; - return this; - } - - /** - * Sets the suffix to append to negative numbers. Locale-specific symbols will be substituted into - * the string according to Unicode Technical Standard #35 (LDML). - * - *

For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}. - * - * @param negativeSuffixPattern The CharSequence to append to negative numbers after locale symbol - * substitutions take place. - * @return The property bag, for chaining. - * @see PositiveNegativeAffixFormat - * @see #setNegativeSuffix - */ - public DecimalFormatProperties setNegativeSuffixPattern(String negativeSuffixPattern) { - this.negativeSuffixPattern = negativeSuffixPattern; - return this; - } - - /** - * Sets the location where the padding string is to be inserted to maintain the padding width: one - * of BEFORE_PREFIX, AFTER_PREFIX, BEFORE_SUFFIX, or AFTER_SUFFIX. - * - *

Must be used in conjunction with {@link #setFormatWidth}. - * - * @param padPosition The output width. - * @return The property bag, for chaining. - * @see #setFormatWidth - */ - public DecimalFormatProperties setPadPosition(PadPosition paddingLocation) { - this.padPosition = paddingLocation; - return this; - } - - /** - * Sets the string used for padding. The string should contain a single character or grapheme - * cluster. - * - *

Must be used in conjunction with {@link #setFormatWidth}. - * - * @param paddingString The padding string. Defaults to an ASCII space (U+0020). - * @return The property bag, for chaining. - * @see #setFormatWidth - */ - public DecimalFormatProperties setPadString(String paddingString) { - this.padString = paddingString; - return this; - } - - /** - * Whether to require cases to match when parsing strings; default is true. Case sensitivity - * applies to prefixes, suffixes, the exponent separator, the symbol "NaN", and the infinity - * symbol. Grouping separators, decimal separators, and padding are always case-sensitive. - * Currencies are always case-insensitive. - * - *

This setting is ignored in fast mode. In fast mode, strings are always compared in a - * case-sensitive way. - * - * @param parseCaseSensitive true to be case-sensitive when parsing; false to allow any case. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setParseCaseSensitive(boolean parseCaseSensitive) { - this.parseCaseSensitive = parseCaseSensitive; - return this; - } - - /** - * Sets the strategy used during parsing when a code point needs to be interpreted as either a - * decimal separator or a grouping separator. - * - *

The comma, period, space, and apostrophe have different meanings in different locales. For - * example, in en-US and most American locales, the period is used as a decimal - * separator, but in es-PY and most European locales, it is used as a grouping separator. - * - *

Suppose you are in fr-FR the parser encounters the string "1.234". In - * fr-FR, the grouping is a space and the decimal is a comma. The grouping mode - * is a mechanism to let you specify whether to accept the string as 1234 (GroupingMode.DEFAULT) - * or whether to reject it since the separators don't match (GroupingMode.RESTRICTED). - * - *

When resolving grouping separators, it is the equivalence class of separators that - * is considered. For example, a period is seen as equal to a fixed set of other period-like - * characters. - * - * @param parseGroupingMode The {@link GroupingMode} to use; either DEFAULT or RESTRICTED. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setParseGroupingMode(GroupingMode parseGroupingMode) { - this.parseGroupingMode = parseGroupingMode; - return this; - } - - /** - * Whether to ignore the fractional part of numbers. For example, parses "123.4" to "123" instead - * of "123.4". - * - * @param parseIntegerOnly true to parse integers only; false to parse integers with their - * fraction parts - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setParseIntegerOnly(boolean parseIntegerOnly) { - this.parseIntegerOnly = parseIntegerOnly; - return this; - } - - /** - * Controls certain rules for how strict this parser is when reading strings. See {@link - * ParseMode#LENIENT} and {@link ParseMode#STRICT}. - * - * @param parseMode Either {@link ParseMode#LENIENT} or {@link ParseMode#STRICT}. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setParseMode(ParseMode parseMode) { - this.parseMode = parseMode; - return this; - } - - /** - * Whether to ignore the exponential part of numbers. For example, parses "123E4" to "123" instead - * of "1230000". - * - * @param parseIgnoreExponent true to ignore exponents; false to parse them. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setParseNoExponent(boolean parseNoExponent) { - this.parseNoExponent = parseNoExponent; - return this; - } - - /** - * Whether to always return a BigDecimal from {@link Parse#parse} and all other parse methods. By - * default, a Long or a BigInteger are returned when possible. - * - * @param parseToBigDecimal true to always return a BigDecimal; false to return a Long or a - * BigInteger when possible. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setParseToBigDecimal(boolean parseToBigDecimal) { - this.parseToBigDecimal = parseToBigDecimal; - return this; - } - - /** - * Sets the PluralRules object to use instead of the default for the locale. - * - * @param pluralRules The object to reference. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setPluralRules(PluralRules pluralRules) { - this.pluralRules = pluralRules; - return this; - } - - /** - * Sets the prefix to prepend to positive numbers. The prefix will be interpreted literally. For - * example, if you set a positive prefix of p, then the number 123 will be formatted - * as "p123" in the locale en-US. - * - *

For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}. - * - * @param positivePrefix The CharSequence to prepend to positive numbers. - * @return The property bag, for chaining. - * @see PositiveNegativeAffixFormat - * @see #setPositivePrefixPattern - */ - public DecimalFormatProperties setPositivePrefix(String positivePrefix) { - this.positivePrefix = positivePrefix; - return this; - } - - /** - * Sets the prefix to prepend to positive numbers. Locale-specific symbols will be substituted - * into the string according to Unicode Technical Standard #35 (LDML). - * - *

For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}. - * - * @param positivePrefixPattern The CharSequence to prepend to positive numbers after locale - * symbol substitutions take place. - * @return The property bag, for chaining. - * @see PositiveNegativeAffixFormat - * @see #setPositivePrefix - */ - public DecimalFormatProperties setPositivePrefixPattern(String positivePrefixPattern) { - this.positivePrefixPattern = positivePrefixPattern; - return this; - } - - /** - * Sets the suffix to append to positive numbers. The suffix will be interpreted literally. For - * example, if you set a positive suffix of p, then the number 123 will be formatted - * as "123p" in the locale en-US. - * - *

For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}. - * - * @param positiveSuffix The CharSequence to append to positive numbers. - * @return The property bag, for chaining. - * @see PositiveNegativeAffixFormat - * @see #setPositiveSuffixPattern - */ - public DecimalFormatProperties setPositiveSuffix(String positiveSuffix) { - this.positiveSuffix = positiveSuffix; - return this; - } - - /** - * Sets the suffix to append to positive numbers. Locale-specific symbols will be substituted into - * the string according to Unicode Technical Standard #35 (LDML). - * - *

For more information on prefixes and suffixes, see {@link PositiveNegativeAffixFormat}. - * - * @param positiveSuffixPattern The CharSequence to append to positive numbers after locale symbol - * substitutions take place. - * @return The property bag, for chaining. - * @see PositiveNegativeAffixFormat - * @see #setPositiveSuffix - */ - public DecimalFormatProperties setPositiveSuffixPattern(String positiveSuffixPattern) { - this.positiveSuffixPattern = positiveSuffixPattern; - return this; - } - - /** - * Sets the increment to which to round numbers. For example, with a rounding interval of 0.05, - * the number 11.17 would be formatted as "11.15" in locale en-US with the default - * rounding mode. - * - *

You can use either a rounding increment or significant digits, but not both at the same - * time. - * - *

The rounding increment can be specified in a pattern string. For example, the pattern - * "#,##0.05" corresponds to a rounding interval of 0.05 with 1 minimum integer digit and a - * grouping size of 3. - * - * @param roundingIncrement The interval to which to round. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setRoundingIncrement(BigDecimal roundingIncrement) { - this.roundingIncrement = roundingIncrement; - return this; - } - - /** - * Sets the rounding mode, which determines under which conditions extra decimal places are - * rounded either up or down. See {@link RoundingMode} for details on the choices of rounding - * mode. The default if not set explicitly is {@link RoundingMode#HALF_EVEN}. - * - *

This setting is ignored if {@link #setMathContext} is used. - * - * @param roundingMode The rounding mode to use when rounding is required. - * @return The property bag, for chaining. - * @see RoundingMode - * @see #setMathContext - */ - public DecimalFormatProperties setRoundingMode(RoundingMode roundingMode) { - this.roundingMode = roundingMode; - return this; - } - - /** - * Sets the number of digits between grouping separators higher than the least-significant - * grouping separator. For example, the locale hi uses a primary grouping size of 3 and a - * secondary grouping size of 2, so the number 1234567 would be formatted as "12,34,567". - * - *

The two levels of grouping separators can be specified in the pattern string. For example, - * the hi locale's default decimal format pattern is "#,##,##0.###". - * - * @param secondaryGroupingSize The secondary grouping size. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setSecondaryGroupingSize(int secondaryGroupingSize) { - this.secondaryGroupingSize = secondaryGroupingSize; - return this; - } - - /** - * Sets whether to always display of a plus sign on positive numbers. - * - *

If the location of the negative sign is specified by the decimal format pattern (or by the - * negative prefix/suffix pattern methods), a plus sign is substituted into that location, in - * accordance with Unicode Technical Standard #35 (LDML) section 3.2.1. Otherwise, the plus sign - * is prepended to the number. For example, if the decimal format pattern #;#- is - * used, then formatting 123 would result in "123+" in the locale en-US. - * - *

This method should be used instead of setting the positive prefix/suffix. The - * behavior is undefined if alwaysShowPlusSign is set but the positive prefix/suffix already - * contains a plus sign. - * - * @param plusSignAlwaysShown Whether positive numbers should display a plus sign. - * @return The property bag, for chaining. - */ - public DecimalFormatProperties setSignAlwaysShown(boolean signAlwaysShown) { - this.signAlwaysShown = signAlwaysShown; - return this; - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - result.append(""); - return result.toString(); - } - - /** - * Appends a string containing properties that differ from the default, but without being - * surrounded by <Properties>. - */ - public void toStringBare(StringBuilder result) { - Field[] fields = DecimalFormatProperties.class.getDeclaredFields(); - for (Field field : fields) { - Object myValue, defaultValue; - try { - myValue = field.get(this); - defaultValue = field.get(DEFAULT); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - continue; - } catch (IllegalAccessException e) { - e.printStackTrace(); - continue; - } - if (myValue == null && defaultValue == null) { - continue; - } else if (myValue == null || defaultValue == null) { - result.append(" " + field.getName() + ":" + myValue); - } else if (!myValue.equals(defaultValue)) { - result.append(" " + field.getName() + ":" + myValue); - } + private boolean _equals(DecimalFormatProperties other) { + boolean eq = true; + eq = eq && _equalsHelper(compactCustomData, other.compactCustomData); + eq = eq && _equalsHelper(compactStyle, other.compactStyle); + eq = eq && _equalsHelper(currency, other.currency); + eq = eq && _equalsHelper(currencyPluralInfo, other.currencyPluralInfo); + eq = eq && _equalsHelper(currencyUsage, other.currencyUsage); + eq = eq && _equalsHelper(decimalPatternMatchRequired, other.decimalPatternMatchRequired); + eq = eq && _equalsHelper(decimalSeparatorAlwaysShown, other.decimalSeparatorAlwaysShown); + eq = eq && _equalsHelper(exponentSignAlwaysShown, other.exponentSignAlwaysShown); + eq = eq && _equalsHelper(formatWidth, other.formatWidth); + eq = eq && _equalsHelper(groupingSize, other.groupingSize); + eq = eq && _equalsHelper(magnitudeMultiplier, other.magnitudeMultiplier); + eq = eq && _equalsHelper(mathContext, other.mathContext); + eq = eq && _equalsHelper(maximumFractionDigits, other.maximumFractionDigits); + eq = eq && _equalsHelper(maximumIntegerDigits, other.maximumIntegerDigits); + eq = eq && _equalsHelper(maximumSignificantDigits, other.maximumSignificantDigits); + eq = eq && _equalsHelper(minimumExponentDigits, other.minimumExponentDigits); + eq = eq && _equalsHelper(minimumFractionDigits, other.minimumFractionDigits); + eq = eq && _equalsHelper(minimumGroupingDigits, other.minimumGroupingDigits); + eq = eq && _equalsHelper(minimumIntegerDigits, other.minimumIntegerDigits); + eq = eq && _equalsHelper(minimumSignificantDigits, other.minimumSignificantDigits); + eq = eq && _equalsHelper(multiplier, other.multiplier); + eq = eq && _equalsHelper(negativePrefix, other.negativePrefix); + eq = eq && _equalsHelper(negativePrefixPattern, other.negativePrefixPattern); + eq = eq && _equalsHelper(negativeSuffix, other.negativeSuffix); + eq = eq && _equalsHelper(negativeSuffixPattern, other.negativeSuffixPattern); + eq = eq && _equalsHelper(padPosition, other.padPosition); + eq = eq && _equalsHelper(padString, other.padString); + eq = eq && _equalsHelper(parseCaseSensitive, other.parseCaseSensitive); + eq = eq && _equalsHelper(parseGroupingMode, other.parseGroupingMode); + eq = eq && _equalsHelper(parseIntegerOnly, other.parseIntegerOnly); + eq = eq && _equalsHelper(parseMode, other.parseMode); + eq = eq && _equalsHelper(parseNoExponent, other.parseNoExponent); + eq = eq && _equalsHelper(parseToBigDecimal, other.parseToBigDecimal); + eq = eq && _equalsHelper(pluralRules, other.pluralRules); + eq = eq && _equalsHelper(positivePrefix, other.positivePrefix); + eq = eq && _equalsHelper(positivePrefixPattern, other.positivePrefixPattern); + eq = eq && _equalsHelper(positiveSuffix, other.positiveSuffix); + eq = eq && _equalsHelper(positiveSuffixPattern, other.positiveSuffixPattern); + eq = eq && _equalsHelper(roundingIncrement, other.roundingIncrement); + eq = eq && _equalsHelper(roundingMode, other.roundingMode); + eq = eq && _equalsHelper(secondaryGroupingSize, other.secondaryGroupingSize); + eq = eq && _equalsHelper(signAlwaysShown, other.signAlwaysShown); + return eq; } - } - /** - * Custom serialization: save fields along with their name, so that fields can be easily added in - * the future in any order. Only save fields that differ from their default value. - */ - private void writeObject(ObjectOutputStream oos) throws IOException { - writeObjectImpl(oos); - } + private boolean _equalsHelper(boolean mine, boolean theirs) { + return mine == theirs; + } - /* package-private */ void writeObjectImpl(ObjectOutputStream oos) throws IOException { - oos.defaultWriteObject(); + private boolean _equalsHelper(int mine, int theirs) { + return mine == theirs; + } - // Extra int for possible future use - oos.writeInt(0); + private boolean _equalsHelper(Object mine, Object theirs) { + if (mine == theirs) + return true; + if (mine == null) + return false; + return mine.equals(theirs); + } - ArrayList fieldsToSerialize = new ArrayList(); - ArrayList valuesToSerialize = new ArrayList(); - Field[] fields = DecimalFormatProperties.class.getDeclaredFields(); - for (Field field : fields) { - if (Modifier.isStatic(field.getModifiers())) { - continue; - } - try { - Object myValue = field.get(this); - if (myValue == null) { - // All *Object* values default to null; no need to serialize. - continue; + private int _hashCode() { + int hashCode = 0; + hashCode ^= _hashCodeHelper(compactCustomData); + hashCode ^= _hashCodeHelper(compactStyle); + hashCode ^= _hashCodeHelper(currency); + hashCode ^= _hashCodeHelper(currencyPluralInfo); + hashCode ^= _hashCodeHelper(currencyUsage); + hashCode ^= _hashCodeHelper(decimalPatternMatchRequired); + hashCode ^= _hashCodeHelper(decimalSeparatorAlwaysShown); + hashCode ^= _hashCodeHelper(exponentSignAlwaysShown); + hashCode ^= _hashCodeHelper(formatWidth); + hashCode ^= _hashCodeHelper(groupingSize); + hashCode ^= _hashCodeHelper(magnitudeMultiplier); + hashCode ^= _hashCodeHelper(mathContext); + hashCode ^= _hashCodeHelper(maximumFractionDigits); + hashCode ^= _hashCodeHelper(maximumIntegerDigits); + hashCode ^= _hashCodeHelper(maximumSignificantDigits); + hashCode ^= _hashCodeHelper(minimumExponentDigits); + hashCode ^= _hashCodeHelper(minimumFractionDigits); + hashCode ^= _hashCodeHelper(minimumGroupingDigits); + hashCode ^= _hashCodeHelper(minimumIntegerDigits); + hashCode ^= _hashCodeHelper(minimumSignificantDigits); + hashCode ^= _hashCodeHelper(multiplier); + hashCode ^= _hashCodeHelper(negativePrefix); + hashCode ^= _hashCodeHelper(negativePrefixPattern); + hashCode ^= _hashCodeHelper(negativeSuffix); + hashCode ^= _hashCodeHelper(negativeSuffixPattern); + hashCode ^= _hashCodeHelper(padPosition); + hashCode ^= _hashCodeHelper(padString); + hashCode ^= _hashCodeHelper(parseCaseSensitive); + hashCode ^= _hashCodeHelper(parseGroupingMode); + hashCode ^= _hashCodeHelper(parseIntegerOnly); + hashCode ^= _hashCodeHelper(parseMode); + hashCode ^= _hashCodeHelper(parseNoExponent); + hashCode ^= _hashCodeHelper(parseToBigDecimal); + hashCode ^= _hashCodeHelper(pluralRules); + hashCode ^= _hashCodeHelper(positivePrefix); + hashCode ^= _hashCodeHelper(positivePrefixPattern); + hashCode ^= _hashCodeHelper(positiveSuffix); + hashCode ^= _hashCodeHelper(positiveSuffixPattern); + hashCode ^= _hashCodeHelper(roundingIncrement); + hashCode ^= _hashCodeHelper(roundingMode); + hashCode ^= _hashCodeHelper(secondaryGroupingSize); + hashCode ^= _hashCodeHelper(signAlwaysShown); + return hashCode; + } + + private int _hashCodeHelper(boolean value) { + return value ? 1 : 0; + } + + private int _hashCodeHelper(int value) { + return value * 13; + } + + private int _hashCodeHelper(Object value) { + if (value == null) + return 0; + return value.hashCode(); + } + + public DecimalFormatProperties clear() { + return _clear(); + } + + /** Creates and returns a shallow copy of the property bag. */ + @Override + public DecimalFormatProperties clone() { + // super.clone() returns a shallow copy. + try { + return (DecimalFormatProperties) super.clone(); + } catch (CloneNotSupportedException e) { + // Should never happen since super is Object + throw new UnsupportedOperationException(e); } - Object defaultValue = field.get(DEFAULT); - if (!myValue.equals(defaultValue)) { - fieldsToSerialize.add(field); - valuesToSerialize.add(myValue); + } + + /** + * Shallow-copies the properties from the given property bag into this property bag. + * + * @param other + * The property bag from which to copy and which will not be modified. + * @return The current property bag (the one modified by this operation), for chaining. + */ + public DecimalFormatProperties copyFrom(DecimalFormatProperties other) { + return _copyFrom(other); + } + + @Override + public boolean equals(Object other) { + if (other == null) + return false; + if (this == other) + return true; + if (!(other instanceof DecimalFormatProperties)) + return false; + return _equals((DecimalFormatProperties) other); + } + + /// BEGIN GETTERS/SETTERS /// + + public Map> getCompactCustomData() { + return compactCustomData; + } + + public CompactStyle getCompactStyle() { + return compactStyle; + } + + public Currency getCurrency() { + return currency; + } + + public CurrencyPluralInfo getCurrencyPluralInfo() { + return currencyPluralInfo; + } + + public CurrencyUsage getCurrencyUsage() { + return currencyUsage; + } + + public boolean getDecimalPatternMatchRequired() { + return decimalPatternMatchRequired; + } + + public boolean getDecimalSeparatorAlwaysShown() { + return decimalSeparatorAlwaysShown; + } + + public boolean getExponentSignAlwaysShown() { + return exponentSignAlwaysShown; + } + + public int getFormatWidth() { + return formatWidth; + } + + public int getGroupingSize() { + return groupingSize; + } + + public int getMagnitudeMultiplier() { + return magnitudeMultiplier; + } + + public MathContext getMathContext() { + return mathContext; + } + + public int getMaximumFractionDigits() { + return maximumFractionDigits; + } + + public int getMaximumIntegerDigits() { + return maximumIntegerDigits; + } + + public int getMaximumSignificantDigits() { + return maximumSignificantDigits; + } + + public int getMinimumExponentDigits() { + return minimumExponentDigits; + } + + public int getMinimumFractionDigits() { + return minimumFractionDigits; + } + + public int getMinimumGroupingDigits() { + return minimumGroupingDigits; + } + + public int getMinimumIntegerDigits() { + return minimumIntegerDigits; + } + + public int getMinimumSignificantDigits() { + return minimumSignificantDigits; + } + + public BigDecimal getMultiplier() { + return multiplier; + } + + public String getNegativePrefix() { + return negativePrefix; + } + + public String getNegativePrefixPattern() { + return negativePrefixPattern; + } + + public String getNegativeSuffix() { + return negativeSuffix; + } + + public String getNegativeSuffixPattern() { + return negativeSuffixPattern; + } + + public PadPosition getPadPosition() { + return padPosition; + } + + public String getPadString() { + return padString; + } + + public boolean getParseCaseSensitive() { + return parseCaseSensitive; + } + + public GroupingMode getParseGroupingMode() { + return parseGroupingMode; + } + + public boolean getParseIntegerOnly() { + return parseIntegerOnly; + } + + public ParseMode getParseMode() { + return parseMode; + } + + public boolean getParseNoExponent() { + return parseNoExponent; + } + + public boolean getParseToBigDecimal() { + return parseToBigDecimal; + } + + public PluralRules getPluralRules() { + return pluralRules; + } + + public String getPositivePrefix() { + return positivePrefix; + } + + public String getPositivePrefixPattern() { + return positivePrefixPattern; + } + + public String getPositiveSuffix() { + return positiveSuffix; + } + + public String getPositiveSuffixPattern() { + return positiveSuffixPattern; + } + + public BigDecimal getRoundingIncrement() { + return roundingIncrement; + } + + public RoundingMode getRoundingMode() { + return roundingMode; + } + + public int getSecondaryGroupingSize() { + return secondaryGroupingSize; + } + + public boolean getSignAlwaysShown() { + return signAlwaysShown; + } + + @Override + public int hashCode() { + return _hashCode(); + } + + /** Custom serialization: re-create object from serialized properties. */ + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException { + readObjectImpl(ois); + } + + /* package-private */ void readObjectImpl(ObjectInputStream ois) throws IOException, ClassNotFoundException { + ois.defaultReadObject(); + + // Initialize to empty + clear(); + + // Extra int for possible future use + ois.readInt(); + + // 1) How many fields were serialized? + int count = ois.readInt(); + + // 2) Read each field by its name and value + for (int i = 0; i < count; i++) { + String name = (String) ois.readObject(); + Object value = ois.readObject(); + + // Get the field reference + Field field = null; + try { + field = DecimalFormatProperties.class.getDeclaredField(name); + } catch (NoSuchFieldException e) { + // The field name does not exist! Possibly corrupted serialization. Ignore this entry. + continue; + } catch (SecurityException e) { + // Should not happen + throw new AssertionError(e); + } + + // NOTE: If the type of a field were changed in the future, this would be the place to check: + // If the variable `value` is the old type, perform any conversions necessary. + + // Save value into the field + try { + field.set(this, value); + } catch (IllegalArgumentException e) { + // Should not happen + throw new AssertionError(e); + } catch (IllegalAccessException e) { + // Should not happen + throw new AssertionError(e); + } } - } catch (IllegalArgumentException e) { - // Should not happen - throw new AssertionError(e); - } catch (IllegalAccessException e) { - // Should not happen - throw new AssertionError(e); - } } - // 1) How many fields are to be serialized? - int count = fieldsToSerialize.size(); - oos.writeInt(count); - - // 2) Write each field with its name and value - for (int i = 0; i < count; i++) { - Field field = fieldsToSerialize.get(i); - Object value = valuesToSerialize.get(i); - oos.writeObject(field.getName()); - oos.writeObject(value); + /** + * Specifies custom data to be used instead of CLDR data when constructing a CompactDecimalFormat. The argument + * should be a map with the following structure: + * + *
+     * {
+     *   "1000": {
+     *     "one": "0 thousand",
+     *     "other": "0 thousand"
+     *   },
+     *   "10000": {
+     *     "one": "00 thousand",
+     *     "other": "00 thousand"
+     *   },
+     *   // ...
+     * }
+     * 
+ * + * This API endpoint is used by the CLDR Survey Tool. + * + * @param compactCustomData + * A map with the above structure. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setCompactCustomData(Map> compactCustomData) { + // TODO: compactCustomData is not immutable. + this.compactCustomData = compactCustomData; + return this; + } + + /** + * Use compact decimal formatting with the specified {@link CompactStyle}. CompactStyle.SHORT produces output like + * "10K" in locale en-US, whereas CompactStyle.LONG produces output like "10 thousand" in that locale. + * + * @param compactStyle + * The style of prefixes/suffixes to append. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setCompactStyle(CompactStyle compactStyle) { + this.compactStyle = compactStyle; + return this; + } + + /** + * Use the specified currency to substitute currency placeholders ('¤') in the pattern string. + * + * @param currency + * The currency. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setCurrency(Currency currency) { + this.currency = currency; + return this; + } + + /** + * Use the specified {@link CurrencyPluralInfo} instance when formatting currency long names. + * + * @param currencyPluralInfo + * The currency plural info object. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setCurrencyPluralInfo(CurrencyPluralInfo currencyPluralInfo) { + // TODO: In order to maintain immutability, we have to perform a clone here. + // It would be better to just retire CurrencyPluralInfo entirely. + if (currencyPluralInfo != null) { + currencyPluralInfo = (CurrencyPluralInfo) currencyPluralInfo.clone(); + } + this.currencyPluralInfo = currencyPluralInfo; + return this; + } + + /** + * Use the specified {@link CurrencyUsage} instance, which provides default rounding rules for the currency in two + * styles, CurrencyUsage.CASH and CurrencyUsage.STANDARD. + * + *

+ * The CurrencyUsage specified here will not be used unless there is a currency placeholder in the pattern. + * + * @param currencyUsage + * The currency usage. Defaults to CurrencyUsage.STANDARD. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setCurrencyUsage(CurrencyUsage currencyUsage) { + this.currencyUsage = currencyUsage; + return this; + } + + /** + * PARSING: Whether to require that the presence of decimal point matches the pattern. If a decimal point is not + * present, but the pattern contained a decimal point, parse will not succeed: null will be returned from + * parse(), and an error index will be set in the {@link ParsePosition}. + * + * @param decimalPatternMatchRequired + * true to set an error if decimal is not present + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setDecimalPatternMatchRequired(boolean decimalPatternMatchRequired) { + this.decimalPatternMatchRequired = decimalPatternMatchRequired; + return this; + } + + /** + * Sets whether to always show the decimal point, even if the number doesn't require one. For example, if always + * show decimal is true, the number 123 would be formatted as "123." in locale en-US. + * + * @param alwaysShowDecimal + * Whether to show the decimal point when it is optional. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setDecimalSeparatorAlwaysShown(boolean alwaysShowDecimal) { + this.decimalSeparatorAlwaysShown = alwaysShowDecimal; + return this; + } + + /** + * Sets whether to show the plus sign in the exponent part of numbers with a zero or positive exponent. For example, + * the number "1200" with the pattern "0.0E0" would be formatted as "1.2E+3" instead of "1.2E3" in en-US. + * + * @param exponentSignAlwaysShown + * Whether to show the plus sign in positive exponents. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setExponentSignAlwaysShown(boolean exponentSignAlwaysShown) { + this.exponentSignAlwaysShown = exponentSignAlwaysShown; + return this; + } + + /** + * Sets the minimum width of the string output by the formatting pipeline. For example, if padding is enabled and + * paddingWidth is set to 6, formatting the number "3.14159" with the pattern "0.00" will result in "··3.14" if '·' + * is your padding string. + * + *

+ * If the number is longer than your padding width, the number will display as if no padding width had been + * specified, which may result in strings longer than the padding width. + * + *

+ * Width is counted in UTF-16 code units. + * + * @param paddingWidth + * The output width. + * @return The property bag, for chaining. + * @see #setPadPosition + * @see #setPadString + */ + public DecimalFormatProperties setFormatWidth(int paddingWidth) { + this.formatWidth = paddingWidth; + return this; + } + + /** + * Sets the number of digits between grouping separators. For example, the en-US locale uses a grouping + * size of 3, so the number 1234567 would be formatted as "1,234,567". For locales whose grouping sizes vary with + * magnitude, see {@link #setSecondaryGroupingSize(int)}. + * + * @param groupingSize + * The primary grouping size. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setGroupingSize(int groupingSize) { + this.groupingSize = groupingSize; + return this; + } + + /** + * Multiply all numbers by this power of ten before formatting. Negative multipliers reduce the magnitude and make + * numbers smaller (closer to zero). + * + * @param magnitudeMultiplier + * The number of powers of ten to scale. + * @return The property bag, for chaining. + * @see #setMultiplier + */ + public DecimalFormatProperties setMagnitudeMultiplier(int magnitudeMultiplier) { + this.magnitudeMultiplier = magnitudeMultiplier; + return this; + } + + /** + * Sets the {@link MathContext} to be used during math and rounding operations. A MathContext encapsulates a + * RoundingMode and the number of significant digits in the output. + * + * @param mathContext + * The math context to use when rounding is required. + * @return The property bag, for chaining. + * @see MathContext + * @see #setRoundingMode + */ + public DecimalFormatProperties setMathContext(MathContext mathContext) { + this.mathContext = mathContext; + return this; + } + + /** + * Sets the maximum number of digits to display after the decimal point. If the number has fewer than this number of + * digits, the number will be rounded off using the rounding mode specified by + * {@link #setRoundingMode(RoundingMode)}. The pattern "#00.0#", for example, corresponds to 2 maximum fraction + * digits, and the number 456.789 would be formatted as "456.79" in locale en-US with the default rounding + * mode. Note that the number 456.999 would be formatted as "457.0" given the same configurations. + * + * @param maximumFractionDigits + * The maximum number of fraction digits to output. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setMaximumFractionDigits(int maximumFractionDigits) { + this.maximumFractionDigits = maximumFractionDigits; + return this; + } + + /** + * Sets the maximum number of digits to display before the decimal point. If the number has more than this number of + * digits, the extra digits will be truncated. For example, if maximum integer digits is 2, and you attempt to + * format the number 1970, you will get "70" in locale en-US. It is not possible to specify the maximum + * integer digits using a pattern string, except in the special case of a scientific format pattern. + * + * @param maximumIntegerDigits + * The maximum number of integer digits to output. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setMaximumIntegerDigits(int maximumIntegerDigits) { + this.maximumIntegerDigits = maximumIntegerDigits; + return this; + } + + /** + * Sets the maximum number of significant digits to display. The number of significant digits is equal to the number + * of digits counted from the leftmost nonzero digit through the rightmost nonzero digit; for example, the number + * "2010" has 3 significant digits. If the number has more significant digits than specified here, the extra + * significant digits will be rounded off using the rounding mode specified by + * {@link #setRoundingMode(RoundingMode)}. For example, if maximum significant digits is 3, the number 1234.56 will + * be formatted as "1230" in locale en-US with the default rounding mode. + * + *

+ * If both maximum significant digits and maximum integer/fraction digits are set at the same time, the behavior is + * undefined. + * + *

+ * The number of significant digits can be specified in a pattern string using the '@' character. For example, the + * pattern "@@#" corresponds to a minimum of 2 and a maximum of 3 significant digits. + * + * @param maximumSignificantDigits + * The maximum number of significant digits to display. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setMaximumSignificantDigits(int maximumSignificantDigits) { + this.maximumSignificantDigits = maximumSignificantDigits; + return this; + } + + /** + * Sets the minimum number of digits to display in the exponent. For example, the number "1200" with the pattern + * "0.0E00", which has 2 exponent digits, would be formatted as "1.2E03" in en-US. + * + * @param minimumExponentDigits + * The minimum number of digits to display in the exponent field. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setMinimumExponentDigits(int minimumExponentDigits) { + this.minimumExponentDigits = minimumExponentDigits; + return this; + } + + /** + * Sets the minimum number of digits to display after the decimal point. If the number has fewer than this number of + * digits, the number will be padded with zeros. The pattern "#00.0#", for example, corresponds to 1 minimum + * fraction digit, and the number 456 would be formatted as "456.0" in locale en-US. + * + * @param minimumFractionDigits + * The minimum number of fraction digits to output. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setMinimumFractionDigits(int minimumFractionDigits) { + this.minimumFractionDigits = minimumFractionDigits; + return this; + } + + /** + * Sets the minimum number of digits required to be beyond the first grouping separator in order to enable grouping. + * For example, if the minimum grouping digits is 2, then 1234 would be formatted as "1234" but 12345 would be + * formatted as "12,345" in en-US. Note that 1234567 would still be formatted as "1,234,567", not + * "1234,567". + * + * @param minimumGroupingDigits + * How many digits must appear before a grouping separator before enabling grouping. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setMinimumGroupingDigits(int minimumGroupingDigits) { + this.minimumGroupingDigits = minimumGroupingDigits; + return this; + } + + /** + * Sets the minimum number of digits to display before the decimal point. If the number has fewer than this number + * of digits, the number will be padded with zeros. The pattern "#00.0#", for example, corresponds to 2 minimum + * integer digits, and the number 5.3 would be formatted as "05.3" in locale en-US. + * + * @param minimumIntegerDigits + * The minimum number of integer digits to output. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setMinimumIntegerDigits(int minimumIntegerDigits) { + this.minimumIntegerDigits = minimumIntegerDigits; + return this; + } + + /** + * Sets the minimum number of significant digits to display. If, after rounding to the number of significant digits + * specified by {@link #setMaximumSignificantDigits}, the number of remaining significant digits is less than the + * minimum, the number will be padded with zeros. For example, if minimum significant digits is 3, the number 5.8 + * will be formatted as "5.80" in locale en-US. Note that minimum significant digits is relevant only when + * numbers have digits after the decimal point. + * + *

+ * If both minimum significant digits and minimum integer/fraction digits are set at the same time, both values will + * be respected, and the one that results in the greater number of padding zeros will be used. For example, + * formatting the number 73 with 3 minimum significant digits and 2 minimum fraction digits will produce "73.00". + * + *

+ * The number of significant digits can be specified in a pattern string using the '@' character. For example, the + * pattern "@@#" corresponds to a minimum of 2 and a maximum of 3 significant digits. + * + * @param minimumSignificantDigits + * The minimum number of significant digits to display. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setMinimumSignificantDigits(int minimumSignificantDigits) { + this.minimumSignificantDigits = minimumSignificantDigits; + return this; + } + + /** + * Multiply all numbers by this amount before formatting. + * + * @param multiplier + * The amount to multiply by. + * @return The property bag, for chaining. + * @see #setMagnitudeMultiplier + */ + public DecimalFormatProperties setMultiplier(BigDecimal multiplier) { + this.multiplier = multiplier; + return this; + } + + /** + * Sets the prefix to prepend to negative numbers. The prefix will be interpreted literally. For example, if you set + * a negative prefix of n, then the number -123 will be formatted as "n123" in the locale + * en-US. Note that if the negative prefix is left unset, the locale's minus sign is used. + * + *

+ * For more information on prefixes and suffixes, see {@link MutablePatternModifier}. + * + * @param negativePrefix + * The CharSequence to prepend to negative numbers. + * @return The property bag, for chaining. + * @see #setNegativePrefixPattern + */ + public DecimalFormatProperties setNegativePrefix(String negativePrefix) { + this.negativePrefix = negativePrefix; + return this; + } + + /** + * Sets the prefix to prepend to negative numbers. Locale-specific symbols will be substituted into the string + * according to Unicode Technical Standard #35 (LDML). + * + *

+ * For more information on prefixes and suffixes, see {@link MutablePatternModifier}. + * + * @param negativePrefixPattern + * The CharSequence to prepend to negative numbers after locale symbol substitutions take place. + * @return The property bag, for chaining. + * @see #setNegativePrefix + */ + public DecimalFormatProperties setNegativePrefixPattern(String negativePrefixPattern) { + this.negativePrefixPattern = negativePrefixPattern; + return this; + } + + /** + * Sets the suffix to append to negative numbers. The suffix will be interpreted literally. For example, if you set + * a suffix prefix of n, then the number -123 will be formatted as "-123n" in the locale + * en-US. Note that the minus sign is prepended by default unless otherwise specified in either the pattern + * string or in one of the {@link #setNegativePrefix} methods. + * + *

+ * For more information on prefixes and suffixes, see {@link MutablePatternModifier}. + * + * @param negativeSuffix + * The CharSequence to append to negative numbers. + * @return The property bag, for chaining. + * @see #setNegativeSuffixPattern + */ + public DecimalFormatProperties setNegativeSuffix(String negativeSuffix) { + this.negativeSuffix = negativeSuffix; + return this; + } + + /** + * Sets the suffix to append to negative numbers. Locale-specific symbols will be substituted into the string + * according to Unicode Technical Standard #35 (LDML). + * + *

+ * For more information on prefixes and suffixes, see {@link MutablePatternModifier}. + * + * @param negativeSuffixPattern + * The CharSequence to append to negative numbers after locale symbol substitutions take place. + * @return The property bag, for chaining. + * @see #setNegativeSuffix + */ + public DecimalFormatProperties setNegativeSuffixPattern(String negativeSuffixPattern) { + this.negativeSuffixPattern = negativeSuffixPattern; + return this; + } + + /** + * Sets the location where the padding string is to be inserted to maintain the padding width: one of BEFORE_PREFIX, + * AFTER_PREFIX, BEFORE_SUFFIX, or AFTER_SUFFIX. + * + *

+ * Must be used in conjunction with {@link #setFormatWidth}. + * + * @param paddingLocation + * The output width. + * @return The property bag, for chaining. + * @see #setFormatWidth + */ + public DecimalFormatProperties setPadPosition(PadPosition paddingLocation) { + this.padPosition = paddingLocation; + return this; + } + + /** + * Sets the string used for padding. The string should contain a single character or grapheme cluster. + * + *

+ * Must be used in conjunction with {@link #setFormatWidth}. + * + * @param paddingString + * The padding string. Defaults to an ASCII space (U+0020). + * @return The property bag, for chaining. + * @see #setFormatWidth + */ + public DecimalFormatProperties setPadString(String paddingString) { + this.padString = paddingString; + return this; + } + + /** + * Whether to require cases to match when parsing strings; default is true. Case sensitivity applies to prefixes, + * suffixes, the exponent separator, the symbol "NaN", and the infinity symbol. Grouping separators, decimal + * separators, and padding are always case-sensitive. Currencies are always case-insensitive. + * + *

+ * This setting is ignored in fast mode. In fast mode, strings are always compared in a case-sensitive way. + * + * @param parseCaseSensitive + * true to be case-sensitive when parsing; false to allow any case. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setParseCaseSensitive(boolean parseCaseSensitive) { + this.parseCaseSensitive = parseCaseSensitive; + return this; + } + + /** + * Sets the strategy used during parsing when a code point needs to be interpreted as either a decimal separator or + * a grouping separator. + * + *

+ * The comma, period, space, and apostrophe have different meanings in different locales. For example, in + * en-US and most American locales, the period is used as a decimal separator, but in es-PY and + * most European locales, it is used as a grouping separator. + * + *

+ * Suppose you are in fr-FR the parser encounters the string "1.234". In fr-FR, the grouping is a + * space and the decimal is a comma. The grouping mode is a mechanism to let you specify whether to accept + * the string as 1234 (GroupingMode.DEFAULT) or whether to reject it since the separators don't match + * (GroupingMode.RESTRICTED). + * + *

+ * When resolving grouping separators, it is the equivalence class of separators that is considered. For + * example, a period is seen as equal to a fixed set of other period-like characters. + * + * @param parseGroupingMode + * The {@link GroupingMode} to use; either DEFAULT or RESTRICTED. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setParseGroupingMode(GroupingMode parseGroupingMode) { + this.parseGroupingMode = parseGroupingMode; + return this; + } + + /** + * Whether to ignore the fractional part of numbers. For example, parses "123.4" to "123" instead of "123.4". + * + * @param parseIntegerOnly + * true to parse integers only; false to parse integers with their fraction parts + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setParseIntegerOnly(boolean parseIntegerOnly) { + this.parseIntegerOnly = parseIntegerOnly; + return this; + } + + /** + * Controls certain rules for how strict this parser is when reading strings. See {@link ParseMode#LENIENT} and + * {@link ParseMode#STRICT}. + * + * @param parseMode + * Either {@link ParseMode#LENIENT} or {@link ParseMode#STRICT}. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setParseMode(ParseMode parseMode) { + this.parseMode = parseMode; + return this; + } + + /** + * Whether to ignore the exponential part of numbers. For example, parses "123E4" to "123" instead of "1230000". + * + * @param parseNoExponent + * true to ignore exponents; false to parse them. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setParseNoExponent(boolean parseNoExponent) { + this.parseNoExponent = parseNoExponent; + return this; + } + + /** + * Whether to always return a BigDecimal from {@link Parse#parse} and all other parse methods. By default, a Long or + * a BigInteger are returned when possible. + * + * @param parseToBigDecimal + * true to always return a BigDecimal; false to return a Long or a BigInteger when possible. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setParseToBigDecimal(boolean parseToBigDecimal) { + this.parseToBigDecimal = parseToBigDecimal; + return this; + } + + /** + * Sets the PluralRules object to use instead of the default for the locale. + * + * @param pluralRules + * The object to reference. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setPluralRules(PluralRules pluralRules) { + this.pluralRules = pluralRules; + return this; + } + + /** + * Sets the prefix to prepend to positive numbers. The prefix will be interpreted literally. For example, if you set + * a positive prefix of p, then the number 123 will be formatted as "p123" in the locale + * en-US. + * + *

+ * For more information on prefixes and suffixes, see {@link MutablePatternModifier}. + * + * @param positivePrefix + * The CharSequence to prepend to positive numbers. + * @return The property bag, for chaining. + * @see #setPositivePrefixPattern + */ + public DecimalFormatProperties setPositivePrefix(String positivePrefix) { + this.positivePrefix = positivePrefix; + return this; + } + + /** + * Sets the prefix to prepend to positive numbers. Locale-specific symbols will be substituted into the string + * according to Unicode Technical Standard #35 (LDML). + * + *

+ * For more information on prefixes and suffixes, see {@link MutablePatternModifier}. + * + * @param positivePrefixPattern + * The CharSequence to prepend to positive numbers after locale symbol substitutions take place. + * @return The property bag, for chaining. + * @see #setPositivePrefix + */ + public DecimalFormatProperties setPositivePrefixPattern(String positivePrefixPattern) { + this.positivePrefixPattern = positivePrefixPattern; + return this; + } + + /** + * Sets the suffix to append to positive numbers. The suffix will be interpreted literally. For example, if you set + * a positive suffix of p, then the number 123 will be formatted as "123p" in the locale + * en-US. + * + *

+ * For more information on prefixes and suffixes, see {@link MutablePatternModifier}. + * + * @param positiveSuffix + * The CharSequence to append to positive numbers. + * @return The property bag, for chaining. + * @see #setPositiveSuffixPattern + */ + public DecimalFormatProperties setPositiveSuffix(String positiveSuffix) { + this.positiveSuffix = positiveSuffix; + return this; + } + + /** + * Sets the suffix to append to positive numbers. Locale-specific symbols will be substituted into the string + * according to Unicode Technical Standard #35 (LDML). + * + *

+ * For more information on prefixes and suffixes, see {@link MutablePatternModifier}. + * + * @param positiveSuffixPattern + * The CharSequence to append to positive numbers after locale symbol substitutions take place. + * @return The property bag, for chaining. + * @see #setPositiveSuffix + */ + public DecimalFormatProperties setPositiveSuffixPattern(String positiveSuffixPattern) { + this.positiveSuffixPattern = positiveSuffixPattern; + return this; + } + + /** + * Sets the increment to which to round numbers. For example, with a rounding interval of 0.05, the number 11.17 + * would be formatted as "11.15" in locale en-US with the default rounding mode. + * + *

+ * You can use either a rounding increment or significant digits, but not both at the same time. + * + *

+ * The rounding increment can be specified in a pattern string. For example, the pattern "#,##0.05" corresponds to a + * rounding interval of 0.05 with 1 minimum integer digit and a grouping size of 3. + * + * @param roundingIncrement + * The interval to which to round. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setRoundingIncrement(BigDecimal roundingIncrement) { + this.roundingIncrement = roundingIncrement; + return this; + } + + /** + * Sets the rounding mode, which determines under which conditions extra decimal places are rounded either up or + * down. See {@link RoundingMode} for details on the choices of rounding mode. The default if not set explicitly is + * {@link RoundingMode#HALF_EVEN}. + * + *

+ * This setting is ignored if {@link #setMathContext} is used. + * + * @param roundingMode + * The rounding mode to use when rounding is required. + * @return The property bag, for chaining. + * @see RoundingMode + * @see #setMathContext + */ + public DecimalFormatProperties setRoundingMode(RoundingMode roundingMode) { + this.roundingMode = roundingMode; + return this; + } + + /** + * Sets the number of digits between grouping separators higher than the least-significant grouping separator. For + * example, the locale hi uses a primary grouping size of 3 and a secondary grouping size of 2, so the + * number 1234567 would be formatted as "12,34,567". + * + *

+ * The two levels of grouping separators can be specified in the pattern string. For example, the hi + * locale's default decimal format pattern is "#,##,##0.###". + * + * @param secondaryGroupingSize + * The secondary grouping size. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setSecondaryGroupingSize(int secondaryGroupingSize) { + this.secondaryGroupingSize = secondaryGroupingSize; + return this; + } + + /** + * Sets whether to always display of a plus sign on positive numbers. + * + *

+ * If the location of the negative sign is specified by the decimal format pattern (or by the negative prefix/suffix + * pattern methods), a plus sign is substituted into that location, in accordance with Unicode Technical Standard + * #35 (LDML) section 3.2.1. Otherwise, the plus sign is prepended to the number. For example, if the decimal format + * pattern #;#- is used, then formatting 123 would result in "123+" in the locale en-US. + * + *

+ * This method should be used instead of setting the positive prefix/suffix. The behavior is undefined if + * alwaysShowPlusSign is set but the positive prefix/suffix already contains a plus sign. + * + * @param signAlwaysShown + * Whether positive numbers should display a plus sign. + * @return The property bag, for chaining. + */ + public DecimalFormatProperties setSignAlwaysShown(boolean signAlwaysShown) { + this.signAlwaysShown = signAlwaysShown; + return this; + } + + @Override + public String toString() { + StringBuilder result = new StringBuilder(); + result.append(""); + return result.toString(); + } + + /** + * Appends a string containing properties that differ from the default, but without being surrounded by + * <Properties>. + */ + public void toStringBare(StringBuilder result) { + Field[] fields = DecimalFormatProperties.class.getDeclaredFields(); + for (Field field : fields) { + Object myValue, defaultValue; + try { + myValue = field.get(this); + defaultValue = field.get(DEFAULT); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + continue; + } catch (IllegalAccessException e) { + e.printStackTrace(); + continue; + } + if (myValue == null && defaultValue == null) { + continue; + } else if (myValue == null || defaultValue == null) { + result.append(" " + field.getName() + ":" + myValue); + } else if (!myValue.equals(defaultValue)) { + result.append(" " + field.getName() + ":" + myValue); + } + } + } + + /** + * Custom serialization: save fields along with their name, so that fields can be easily added in the future in any + * order. Only save fields that differ from their default value. + */ + private void writeObject(ObjectOutputStream oos) throws IOException { + writeObjectImpl(oos); + } + + /* package-private */ void writeObjectImpl(ObjectOutputStream oos) throws IOException { + oos.defaultWriteObject(); + + // Extra int for possible future use + oos.writeInt(0); + + ArrayList fieldsToSerialize = new ArrayList(); + ArrayList valuesToSerialize = new ArrayList(); + Field[] fields = DecimalFormatProperties.class.getDeclaredFields(); + for (Field field : fields) { + if (Modifier.isStatic(field.getModifiers())) { + continue; + } + try { + Object myValue = field.get(this); + if (myValue == null) { + // All *Object* values default to null; no need to serialize. + continue; + } + Object defaultValue = field.get(DEFAULT); + if (!myValue.equals(defaultValue)) { + fieldsToSerialize.add(field); + valuesToSerialize.add(myValue); + } + } catch (IllegalArgumentException e) { + // Should not happen + throw new AssertionError(e); + } catch (IllegalAccessException e) { + // Should not happen + throw new AssertionError(e); + } + } + + // 1) How many fields are to be serialized? + int count = fieldsToSerialize.size(); + oos.writeInt(count); + + // 2) Write each field with its name and value + for (int i = 0; i < count; i++) { + Field field = fieldsToSerialize.get(i); + Object value = valuesToSerialize.get(i); + oos.writeObject(field.getName()); + oos.writeObject(value); + } } - } } diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/CompactNotation.java b/icu4j/main/classes/core/src/com/ibm/icu/number/CompactNotation.java index da412a366c..320878ff26 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/number/CompactNotation.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/number/CompactNotation.java @@ -120,6 +120,7 @@ public class CompactNotation extends Notation { StandardPlural plural = quantity.getStandardPlural(rules); String patternString = data.getPattern(magnitude, plural); + @SuppressWarnings("unused") // see #13177 int numDigits = -1; if (patternString == null) { // Use the default (non-compact) modifier.