diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/FormatQuantity2.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/FormatQuantity2.java index 30931692d7..a423ef0422 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/FormatQuantity2.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/FormatQuantity2.java @@ -85,6 +85,7 @@ public final class FormatQuantity2 extends FormatQuantityBCD { @Override protected void readIntToBcd(int n) { + assert n != 0; long result = 0L; int i = 16; for (; n != 0; n /= 10, i--) { @@ -98,6 +99,7 @@ public final class FormatQuantity2 extends FormatQuantityBCD { @Override protected void readLongToBcd(long n) { + assert n != 0; long result = 0L; int i = 16; for (; n != 0L; n /= 10L, i--) { @@ -111,6 +113,7 @@ public final class FormatQuantity2 extends FormatQuantityBCD { @Override protected void readBigIntegerToBcd(BigInteger n) { + assert n.signum() != 0; long result = 0L; int i = 16; for (; n.signum() != 0; i--) { diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/FormatQuantity3.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/FormatQuantity3.java index 9e25a45a74..5024f47a37 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/FormatQuantity3.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/FormatQuantity3.java @@ -99,6 +99,7 @@ public final class FormatQuantity3 extends FormatQuantityBCD { @Override protected void readIntToBcd(int n) { + assert n != 0; int i = 0; for (; n != 0L; n /= 10L, i++) { bcd[i] = (byte) (n % 10); @@ -112,6 +113,7 @@ public final class FormatQuantity3 extends FormatQuantityBCD { @Override protected void readLongToBcd(long n) { + assert n != 0; if (n == Long.MIN_VALUE) { // Can't consume via the normal path. System.arraycopy(LONG_MIN_VALUE, 0, bcd, 0, LONG_MIN_VALUE.length); @@ -129,6 +131,7 @@ public final class FormatQuantity3 extends FormatQuantityBCD { @Override protected void readBigIntegerToBcd(BigInteger n) { + assert n.signum() != 0; int i = 0; for (; n.signum() != 0; i++) { BigInteger[] temp = n.divideAndRemainder(BigInteger.TEN); diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/FormatQuantity4.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/FormatQuantity4.java index 3307fff7e4..f22cca4613 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/FormatQuantity4.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/FormatQuantity4.java @@ -155,6 +155,7 @@ public final class FormatQuantity4 extends FormatQuantityBCD { @Override protected void readIntToBcd(int n) { + assert n != 0; // ints always fit inside the long implementation. long result = 0L; int i = 16; @@ -169,6 +170,7 @@ public final class FormatQuantity4 extends FormatQuantityBCD { @Override protected void readLongToBcd(long n) { + assert n != 0; if (n >= 10000000000000000L) { ensureCapacity(); int i = 0; @@ -194,6 +196,7 @@ public final class FormatQuantity4 extends FormatQuantityBCD { @Override protected void readBigIntegerToBcd(BigInteger n) { + assert n.signum() != 0; ensureCapacity(); // allocate initial byte array int i = 0; for (; n.signum() != 0; i++) { diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/FormatQuantityBCD.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/FormatQuantityBCD.java index a096c2c315..67df9b17a1 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/FormatQuantityBCD.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/FormatQuantityBCD.java @@ -457,8 +457,11 @@ public abstract class FormatQuantityBCD implements FormatQuantity { for (; i <= -22; i += 22) n /= 1e22; n /= DOUBLE_MULTIPLIERS[-i]; } - _setToLong(Math.round(n)); - scale -= fracLength; + long result = Math.round(n); + if (result != 0) { + _setToLong(result); + scale -= fracLength; + } } /** diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/modifiers/ConstantAffixModifier.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/modifiers/ConstantAffixModifier.java index b133bc4872..2eea973956 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/modifiers/ConstantAffixModifier.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/modifiers/ConstantAffixModifier.java @@ -81,8 +81,8 @@ public class ConstantAffixModifier extends Modifier.BaseModifier implements Affi public boolean contentEquals(CharSequence _prefix, CharSequence _suffix) { if (_prefix == null && !prefix.isEmpty()) return false; if (_suffix == null && !suffix.isEmpty()) return false; - if (prefix.length() != _prefix.length()) return false; - if (suffix.length() != _suffix.length()) return false; + if (_prefix != null && prefix.length() != _prefix.length()) return false; + if (_suffix != null && suffix.length() != _suffix.length()) return false; for (int i = 0; i < prefix.length(); i++) { if (prefix.charAt(i) != _prefix.charAt(i)) return false; } diff --git a/icu4j/main/classes/core/src/com/ibm/icu/text/DecimalFormat.java b/icu4j/main/classes/core/src/com/ibm/icu/text/DecimalFormat.java index 1fab6789e4..3a97615f02 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/text/DecimalFormat.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/text/DecimalFormat.java @@ -233,7 +233,7 @@ public class DecimalFormat extends NumberFormat { * Custom serialization: save property bag and symbols; the formatter object can be re-created * from just that amount of information. */ - private void writeObject(ObjectOutputStream oos) throws IOException { + private synchronized void writeObject(ObjectOutputStream oos) throws IOException { // ICU 59 custom serialization. // Write class metadata and serialVersionOnStream field: oos.defaultWriteObject(); @@ -498,14 +498,6 @@ public class DecimalFormat extends NumberFormat { return result; } - private static final ThreadLocal threadLocalCurrencyProperties = - new ThreadLocal() { - @Override - protected Properties initialValue() { - return new Properties(); - } - }; - /** * {@inheritDoc} * @@ -515,7 +507,7 @@ public class DecimalFormat extends NumberFormat { public StringBuffer format(CurrencyAmount currAmt, StringBuffer toAppendTo, FieldPosition pos) { // TODO: This is ugly (although not as ugly as it was in ICU 58). // Currency should be a free parameter, not in property bag. Fix in ICU 60. - Properties cprops = threadLocalCurrencyProperties.get(); + Properties cprops = threadLocalProperties.get(); SingularFormat fmt = null; synchronized (this) { // Use the pre-compiled formatter if possible. Otherwise, copy the properties @@ -544,8 +536,12 @@ public class DecimalFormat extends NumberFormat { */ @Override public Number parse(String text, ParsePosition parsePosition) { + Properties pprops = threadLocalProperties.get(); + synchronized (this) { + pprops.copyFrom(properties); + } // Backwards compatibility: use currency parse mode if this is a currency instance - Number result = Parse.parse(text, parsePosition, properties, symbols); + Number result = Parse.parse(text, parsePosition, pprops, symbols); // Backwards compatibility: return com.ibm.icu.math.BigDecimal if (result instanceof java.math.BigDecimal) { result = new com.ibm.icu.math.BigDecimal((java.math.BigDecimal) result); @@ -1711,7 +1707,7 @@ public class DecimalFormat extends NumberFormat { * @category Currency * @stable ICU 4.2 */ - public CurrencyPluralInfo getCurrencyPluralInfo() { + public synchronized CurrencyPluralInfo getCurrencyPluralInfo() { // CurrencyPluralInfo also is not exported. return properties.getCurrencyPluralInfo(); } @@ -1727,7 +1723,7 @@ public class DecimalFormat extends NumberFormat { * @category Currency * @stable ICU 4.2 */ - public void setCurrencyPluralInfo(CurrencyPluralInfo newInfo) { + public synchronized void setCurrencyPluralInfo(CurrencyPluralInfo newInfo) { properties.setCurrencyPluralInfo(newInfo); refreshFormatter(); } @@ -1978,14 +1974,6 @@ public class DecimalFormat extends NumberFormat { return properties.hashCode(); } - private static final ThreadLocal threadLocalToPatternProperties = - new ThreadLocal() { - @Override - protected Properties initialValue() { - return new Properties(); - } - }; - /** * Returns the default value of toString() with extra DecimalFormat-specific information appended * to the end of the string. This extra information is intended for debugging purposes, and the @@ -2027,8 +2015,7 @@ public class DecimalFormat extends NumberFormat { // to keep affix patterns intact. In particular, pull rounding properties // so that CurrencyUsage is reflected properly. // TODO: Consider putting this logic in PatternString.java instead. - Properties tprops = threadLocalToPatternProperties.get(); - tprops.copyFrom(properties); + Properties tprops = threadLocalProperties.get().copyFrom(properties); if (com.ibm.icu.impl.number.formatters.CurrencyFormat.useCurrency(properties)) { tprops.setMinimumFractionDigits(exportedProperties.getMinimumFractionDigits()); tprops.setMaximumFractionDigits(exportedProperties.getMaximumFractionDigits()); @@ -2060,6 +2047,14 @@ public class DecimalFormat extends NumberFormat { return fq; } + private static final ThreadLocal threadLocalProperties = + new ThreadLocal() { + @Override + protected Properties initialValue() { + return new Properties(); + } + }; + /** Rebuilds the formatter object from the property bag. */ void refreshFormatter() { if (exportedProperties == null) {