summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2010-01-25 23:13:46 -0800
committerElliott Hughes <enh@google.com>2010-01-26 16:05:42 -0800
commitf2d5062b67e57ef00ee81fec67480f0d58d66b50 (patch)
tree2b549c42ac9ab9dab0e2c0a4bb165a40d9e956fb
parentab3c1e059b3df3b81b7945ea160e1c6296811bc4 (diff)
downloadlibcore-f2d5062b67e57ef00ee81fec67480f0d58d66b50.zip
libcore-f2d5062b67e57ef00ee81fec67480f0d58d66b50.tar.gz
libcore-f2d5062b67e57ef00ee81fec67480f0d58d66b50.tar.bz2
Simplify our DecimalFormat.
Both the is-a and has-a hierarchies for our DecimalFormat implementation were over-complicated. This patch starts to address that, and makes cloning twice as fast (50us versus 100us), but not as fast as I'd like (<10us), and without making much of a dent in the time it takes to create a new NumberFormat (550us versus 600us). The speed of cloning is important because Formatter has a hack that uses it, and I want to change NumberFormat so that it always hands out clones... at least until I have time to make "new NumberFormat" acceptably fast. Also fixes DecimalFormat.applyLocalizedPattern (which used to behave as if you'd called applyPattern).
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/text/DecimalFormat.java218
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/text/DecimalFormatSymbols.java268
-rw-r--r--icu/src/main/java/com/ibm/icu4jni/text/NativeDecimalFormat.java26
-rw-r--r--icu/src/main/native/NativeDecimalFormat.cpp124
-rw-r--r--icu/src/main/native/Resources.cpp5
-rw-r--r--luni/src/test/java/java/text/AllTests.java1
-rw-r--r--luni/src/test/java/java/text/DecimalFormatTest.java37
-rw-r--r--text/src/main/java/java/text/DecimalFormat.java185
-rw-r--r--text/src/main/java/java/text/DecimalFormatSymbols.java13
-rw-r--r--text/src/test/java/org/apache/harmony/text/tests/java/text/DecimalFormatTest.java4
10 files changed, 281 insertions, 600 deletions
diff --git a/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormat.java b/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormat.java
index 4b296d5..d995dc6 100644
--- a/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormat.java
+++ b/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormat.java
@@ -18,11 +18,13 @@ package com.ibm.icu4jni.text;
import com.ibm.icu4jni.text.NativeDecimalFormat.UNumberFormatAttribute;
import com.ibm.icu4jni.text.NativeDecimalFormat.UNumberFormatTextAttribute;
+import com.ibm.icu4jni.util.LocaleData;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
+import java.text.DecimalFormatSymbols;
import java.text.FieldPosition;
import java.text.Format;
import java.text.NumberFormat;
@@ -30,19 +32,32 @@ import java.text.ParsePosition;
import java.util.Currency;
import java.util.Locale;
-public class DecimalFormat extends NumberFormat {
-
- private int addr;
-
- private DecimalFormatSymbols symbols;
-
- // fix to be icu4j conform (harmony wants this field to exist)
- // for serialization of java.text.DecimalFormat
- @SuppressWarnings("unused")
- private boolean useExponentialNotation = false;
- @SuppressWarnings("unused")
- private byte minExponentDigits = 0;
-
+public class DecimalFormat {
+ // Constants corresponding to the native type UNumberFormatSymbol, for use with getSymbol/setSymbol.
+ private static final int UNUM_DECIMAL_SEPARATOR_SYMBOL = 0;
+ private static final int UNUM_GROUPING_SEPARATOR_SYMBOL = 1;
+ private static final int UNUM_PATTERN_SEPARATOR_SYMBOL = 2;
+ private static final int UNUM_PERCENT_SYMBOL = 3;
+ private static final int UNUM_ZERO_DIGIT_SYMBOL = 4;
+ private static final int UNUM_DIGIT_SYMBOL = 5;
+ private static final int UNUM_MINUS_SIGN_SYMBOL = 6;
+ private static final int UNUM_PLUS_SIGN_SYMBOL = 7;
+ private static final int UNUM_CURRENCY_SYMBOL = 8;
+ private static final int UNUM_INTL_CURRENCY_SYMBOL = 9;
+ private static final int UNUM_MONETARY_SEPARATOR_SYMBOL = 10;
+ private static final int UNUM_EXPONENTIAL_SYMBOL = 11;
+ private static final int UNUM_PERMILL_SYMBOL = 12;
+ private static final int UNUM_PAD_ESCAPE_SYMBOL = 13;
+ private static final int UNUM_INFINITY_SYMBOL = 14;
+ private static final int UNUM_NAN_SYMBOL = 15;
+ private static final int UNUM_SIGNIFICANT_DIGIT_SYMBOL = 16;
+ private static final int UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL = 17;
+ private static final int UNUM_FORMAT_SYMBOL_COUNT = 18;
+
+ // The address of the ICU DecimalFormat* on the native heap.
+ private final int addr;
+
+ // TODO: store all these in java.text.DecimalFormat instead!
private boolean negPrefNull;
private boolean negSuffNull;
private boolean posPrefNull;
@@ -50,37 +65,52 @@ public class DecimalFormat extends NumberFormat {
/**
* Cache the BigDecimal form of the multiplier. This is null until we've
- * formatted a BigDecimal (with a multipler that is not 1), or the user has
+ * formatted a BigDecimal (with a multiplier that is not 1), or the user has
* explicitly called {@link #setMultiplier(int)} with any multiplier.
*/
private transient BigDecimal multiplierBigDecimal = null;
- public DecimalFormat(String pattern, DecimalFormatSymbols icuSymbols) {
- this.addr = icuSymbols.getAddr();
- this.symbols = icuSymbols;
- applyPattern(pattern);
+ public DecimalFormat(String pattern, Locale locale, DecimalFormatSymbols symbols) {
+ this.addr = NativeDecimalFormat.openDecimalFormat(locale.toString(), pattern);
+ setDecimalFormatSymbols(symbols);
}
+ // Used to implement clone.
+ private DecimalFormat(DecimalFormat other) {
+ this.addr = NativeDecimalFormat.cloneDecimalFormatImpl(other.addr);
+ this.negPrefNull = other.negPrefNull;
+ this.negSuffNull = other.negSuffNull;
+ this.posPrefNull = other.posPrefNull;
+ this.posSuffNull = other.posSuffNull;
+ }
+
+ // TODO: remove this and just have java.text.DecimalFormat.hashCode do the right thing itself.
@Override
public int hashCode() {
- return super.hashCode() * 37 + this.getPositivePrefix().hashCode();
+ return this.getPositivePrefix().hashCode();
}
@Override
public Object clone() {
- String pat = this.toPattern();
- DecimalFormatSymbols sym = (DecimalFormatSymbols) this.symbols.clone();
- DecimalFormat newdf = new DecimalFormat(pat, sym);
- newdf.setMaximumIntegerDigits(this.getMaximumIntegerDigits());
- newdf.setMaximumFractionDigits(this.getMaximumFractionDigits());
- newdf.setMinimumIntegerDigits(this.getMinimumIntegerDigits());
- newdf.setMinimumFractionDigits(this.getMinimumFractionDigits());
- newdf.setGroupingUsed(this.isGroupingUsed());
- newdf.setGroupingSize(this.getGroupingSize());
- return newdf;
+ return new DecimalFormat(this);
}
@Override
+ protected void finalize() {
+ NativeDecimalFormat.closeDecimalFormatImpl(this.addr);
+ }
+
+ /**
+ * Note: this doesn't check that the underlying native DecimalFormat objects' configured
+ * native DecimalFormatSymbols objects are equal. It is assumed that the
+ * caller (java.text.DecimalFormat) will check the java.text.DecimalFormatSymbols objects
+ * instead, for performance.
+ *
+ * This is also unreasonably expensive, calling down to JNI multiple times.
+ *
+ * TODO: remove this and just have java.text.DecimalFormat.equals do the right thing itself.
+ */
+ @Override
public boolean equals(Object object) {
if (object == this) {
return true;
@@ -89,39 +119,47 @@ public class DecimalFormat extends NumberFormat {
return false;
}
DecimalFormat obj = (DecimalFormat) object;
-
- if(obj.addr == this.addr) {
+ if (obj.addr == this.addr) {
return true;
}
+ return obj.toPattern().equals(this.toPattern()) &&
+ obj.isDecimalSeparatorAlwaysShown() == this.isDecimalSeparatorAlwaysShown() &&
+ obj.getGroupingSize() == this.getGroupingSize() &&
+ obj.getMultiplier() == this.getMultiplier() &&
+ obj.getNegativePrefix().equals(this.getNegativePrefix()) &&
+ obj.getNegativeSuffix().equals(this.getNegativeSuffix()) &&
+ obj.getPositivePrefix().equals(this.getPositivePrefix()) &&
+ obj.getPositiveSuffix().equals(this.getPositiveSuffix()) &&
+ obj.getMaximumIntegerDigits() == this.getMaximumIntegerDigits() &&
+ obj.getMaximumFractionDigits() == this.getMaximumFractionDigits() &&
+ obj.getMinimumIntegerDigits() == this.getMinimumIntegerDigits() &&
+ obj.getMinimumFractionDigits() == this.getMinimumFractionDigits() &&
+ obj.isGroupingUsed() == this.isGroupingUsed() &&
+ obj.getCurrency() == this.getCurrency();
+ }
- boolean result = super.equals(object);
-
-
- result &= obj.toPattern().equals(this.toPattern());
- result &= obj.isDecimalSeparatorAlwaysShown() == this.isDecimalSeparatorAlwaysShown();
- result &= obj.getGroupingSize() == this.getGroupingSize();
- result &= obj.getMultiplier() == this.getMultiplier();
- result &= obj.getNegativePrefix().equals(this.getNegativePrefix());
- result &= obj.getNegativeSuffix().equals(this.getNegativeSuffix());
- result &= obj.getPositivePrefix().equals(this.getPositivePrefix());
- result &= obj.getPositiveSuffix().equals(this.getPositiveSuffix());
- result &= obj.getMaximumIntegerDigits() == this.getMaximumIntegerDigits();
- result &= obj.getMaximumFractionDigits() == this.getMaximumFractionDigits();
- result &= obj.getMinimumIntegerDigits() == this.getMinimumIntegerDigits();
- result &= obj.getMinimumFractionDigits() == this.getMinimumFractionDigits();
- result &= obj.isGroupingUsed() == this.isGroupingUsed();
- Currency objCurr = obj.getCurrency();
- Currency thisCurr = this.getCurrency();
- if(objCurr != null) {
- result &= objCurr.getCurrencyCode().equals(thisCurr.getCurrencyCode());
- result &= objCurr.getSymbol().equals(thisCurr.getSymbol());
- result &= objCurr.getDefaultFractionDigits() == thisCurr.getDefaultFractionDigits();
- } else {
- result &= thisCurr == null;
- }
- result &= obj.getDecimalFormatSymbols().equals(this.getDecimalFormatSymbols());
+ /**
+ * Copies the java.text.DecimalFormatSymbols' settings into our native peer.
+ */
+ public void setDecimalFormatSymbols(final java.text.DecimalFormatSymbols dfs) {
+ NativeDecimalFormat.setSymbol(this.addr, UNUM_CURRENCY_SYMBOL, dfs.getCurrencySymbol());
- return result;
+ NativeDecimalFormat.setSymbol(this.addr, UNUM_DECIMAL_SEPARATOR_SYMBOL, dfs.getDecimalSeparator());
+ NativeDecimalFormat.setSymbol(this.addr, UNUM_DIGIT_SYMBOL, dfs.getDigit());
+
+ char groupingSeparator = dfs.getGroupingSeparator();
+ NativeDecimalFormat.setSymbol(this.addr, UNUM_GROUPING_SEPARATOR_SYMBOL, groupingSeparator);
+ NativeDecimalFormat.setSymbol(this.addr, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, groupingSeparator);
+
+ NativeDecimalFormat.setSymbol(this.addr, UNUM_INFINITY_SYMBOL, dfs.getInfinity());
+ NativeDecimalFormat.setSymbol(this.addr, UNUM_INTL_CURRENCY_SYMBOL, dfs.getInternationalCurrencySymbol());
+ NativeDecimalFormat.setSymbol(this.addr, UNUM_MINUS_SIGN_SYMBOL, dfs.getMinusSign());
+ NativeDecimalFormat.setSymbol(this.addr, UNUM_MONETARY_SEPARATOR_SYMBOL, dfs.getMonetaryDecimalSeparator());
+ NativeDecimalFormat.setSymbol(this.addr, UNUM_NAN_SYMBOL, dfs.getNaN());
+ NativeDecimalFormat.setSymbol(this.addr, UNUM_PATTERN_SEPARATOR_SYMBOL, dfs.getPatternSeparator());
+ NativeDecimalFormat.setSymbol(this.addr, UNUM_PERCENT_SYMBOL, dfs.getPercent());
+ NativeDecimalFormat.setSymbol(this.addr, UNUM_PERMILL_SYMBOL, dfs.getPerMill());
+ NativeDecimalFormat.setSymbol(this.addr, UNUM_ZERO_DIGIT_SYMBOL, dfs.getZeroDigit());
}
private BigDecimal applyMultiplier(BigDecimal valBigDecimal) {
@@ -132,7 +170,6 @@ public class DecimalFormat extends NumberFormat {
return valBigDecimal.multiply(multiplierBigDecimal);
}
- @Override
public StringBuffer format(Object value, StringBuffer buffer, FieldPosition field) {
if (!(value instanceof Number)) {
throw new IllegalArgumentException();
@@ -170,7 +207,6 @@ public class DecimalFormat extends NumberFormat {
}
}
- @Override
public StringBuffer format(long value, StringBuffer buffer, FieldPosition field) {
if (buffer == null || field == null) {
throw new NullPointerException();
@@ -180,7 +216,6 @@ public class DecimalFormat extends NumberFormat {
return buffer;
}
- @Override
public StringBuffer format(double value, StringBuffer buffer, FieldPosition field) {
if (buffer == null || field == null) {
throw new NullPointerException();
@@ -191,30 +226,13 @@ public class DecimalFormat extends NumberFormat {
}
public void applyLocalizedPattern(String pattern) {
- if (pattern == null) {
- throw new NullPointerException("pattern was null");
- }
- try {
- NativeDecimalFormat.applyPatternImpl(this.addr, false, pattern);
- } catch(RuntimeException re) {
- throw new IllegalArgumentException(
- "applying localized pattern failed for pattern: " + pattern, re);
- }
+ NativeDecimalFormat.applyPattern(this.addr, true, pattern);
}
public void applyPattern(String pattern) {
- if (pattern == null) {
- throw new NullPointerException("pattern was null");
- }
- try {
- NativeDecimalFormat.applyPatternImpl(this.addr, false, pattern);
- } catch(RuntimeException re) {
- throw new IllegalArgumentException(
- "applying pattern failed for pattern: " + pattern, re);
- }
+ NativeDecimalFormat.applyPattern(this.addr, false, pattern);
}
- @Override
public AttributedCharacterIterator formatToCharacterIterator(Object object) {
if (!(object instanceof Number)) {
throw new IllegalArgumentException();
@@ -283,40 +301,38 @@ public class DecimalFormat extends NumberFormat {
return NativeDecimalFormat.toPatternImpl(this.addr, false);
}
- @Override
public Number parse(String string, ParsePosition position) {
return NativeDecimalFormat.parse(addr, string, position);
}
// start getter and setter
- @Override
public int getMaximumFractionDigits() {
- return NativeDecimalFormat.getAttribute(this .addr,
+ return NativeDecimalFormat.getAttribute(this.addr,
UNumberFormatAttribute.UNUM_MAX_FRACTION_DIGITS.ordinal());
}
- @Override
public int getMaximumIntegerDigits() {
- return NativeDecimalFormat.getAttribute(this .addr,
+ return NativeDecimalFormat.getAttribute(this.addr,
UNumberFormatAttribute.UNUM_MAX_INTEGER_DIGITS.ordinal());
}
- @Override
public int getMinimumFractionDigits() {
- return NativeDecimalFormat.getAttribute(this .addr,
+ return NativeDecimalFormat.getAttribute(this.addr,
UNumberFormatAttribute.UNUM_MIN_FRACTION_DIGITS.ordinal());
}
- @Override
public int getMinimumIntegerDigits() {
- return NativeDecimalFormat.getAttribute(this .addr,
+ return NativeDecimalFormat.getAttribute(this.addr,
UNumberFormatAttribute.UNUM_MIN_INTEGER_DIGITS.ordinal());
}
- @Override
public Currency getCurrency() {
- return this.symbols.getCurrency();
+ String curr = NativeDecimalFormat.getSymbol(this.addr, UNUM_INTL_CURRENCY_SYMBOL);
+ if (curr.equals("") || curr.equals("\u00a4\u00a4")) {
+ return null;
+ }
+ return Currency.getInstance(curr);
}
public int getGroupingSize() {
@@ -366,35 +382,25 @@ public class DecimalFormat extends NumberFormat {
UNumberFormatAttribute.UNUM_DECIMAL_ALWAYS_SHOWN.ordinal()) != 0;
}
- @Override
public boolean isParseIntegerOnly() {
return NativeDecimalFormat.getAttribute(this.addr,
UNumberFormatAttribute.UNUM_PARSE_INT_ONLY.ordinal()) != 0;
}
- @Override
public boolean isGroupingUsed() {
return NativeDecimalFormat.getAttribute(this.addr,
UNumberFormatAttribute.UNUM_GROUPING_USED.ordinal()) != 0;
}
- public DecimalFormatSymbols getDecimalFormatSymbols() {
- return this.symbols;
- }
-
- public void setDecimalFormatSymbols(DecimalFormatSymbols icuSymbols) {
- this.symbols = icuSymbols;
- }
-
public void setDecimalSeparatorAlwaysShown(boolean value) {
int i = value ? -1 : 0;
NativeDecimalFormat.setAttribute(this.addr,
UNumberFormatAttribute.UNUM_DECIMAL_ALWAYS_SHOWN.ordinal(), i);
}
- @Override
public void setCurrency(Currency currency) {
- this.symbols.setCurrency(currency);
+ NativeDecimalFormat.setSymbol(this.addr, UNUM_CURRENCY_SYMBOL, currency.getSymbol());
+ NativeDecimalFormat.setSymbol(this.addr, UNUM_INTL_CURRENCY_SYMBOL, currency.getCurrencyCode());
}
public void setGroupingSize(int value) {
@@ -402,32 +408,27 @@ public class DecimalFormat extends NumberFormat {
UNumberFormatAttribute.UNUM_GROUPING_SIZE.ordinal(), value);
}
- @Override
public void setGroupingUsed(boolean value) {
int i = value ? -1 : 0;
NativeDecimalFormat.setAttribute(this.addr,
UNumberFormatAttribute.UNUM_GROUPING_USED.ordinal(), i);
}
- @Override
public void setMaximumFractionDigits(int value) {
NativeDecimalFormat.setAttribute(this.addr,
UNumberFormatAttribute.UNUM_MAX_FRACTION_DIGITS.ordinal(), value);
}
- @Override
public void setMaximumIntegerDigits(int value) {
NativeDecimalFormat.setAttribute(this.addr,
UNumberFormatAttribute.UNUM_MAX_INTEGER_DIGITS.ordinal(), value);
}
- @Override
public void setMinimumFractionDigits(int value) {
NativeDecimalFormat.setAttribute(this.addr,
UNumberFormatAttribute.UNUM_MIN_FRACTION_DIGITS.ordinal(), value);
}
- @Override
public void setMinimumIntegerDigits(int value) {
NativeDecimalFormat.setAttribute(this.addr,
UNumberFormatAttribute.UNUM_MIN_INTEGER_DIGITS.ordinal(), value);
@@ -476,7 +477,6 @@ public class DecimalFormat extends NumberFormat {
}
}
- @Override
public void setParseIntegerOnly(boolean value) {
int i = value ? -1 : 0;
NativeDecimalFormat.setAttribute(this.addr,
diff --git a/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormatSymbols.java b/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormatSymbols.java
deleted file mode 100644
index 2d5ae02..0000000
--- a/icu/src/main/java/com/ibm/icu4jni/text/DecimalFormatSymbols.java
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.ibm.icu4jni.text;
-
-import com.ibm.icu4jni.util.LocaleData;
-
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import java.util.Currency;
-import java.util.Locale;
-import java.util.ResourceBundle;
-
-public class DecimalFormatSymbols implements Cloneable {
-
- // Constants corresponding to the native type UNumberFormatSymbol, for use with getSymbol/setSymbol.
- private static final int UNUM_DECIMAL_SEPARATOR_SYMBOL = 0;
- private static final int UNUM_GROUPING_SEPARATOR_SYMBOL = 1;
- private static final int UNUM_PATTERN_SEPARATOR_SYMBOL = 2;
- private static final int UNUM_PERCENT_SYMBOL = 3;
- private static final int UNUM_ZERO_DIGIT_SYMBOL = 4;
- private static final int UNUM_DIGIT_SYMBOL = 5;
- private static final int UNUM_MINUS_SIGN_SYMBOL = 6;
- private static final int UNUM_PLUS_SIGN_SYMBOL = 7;
- private static final int UNUM_CURRENCY_SYMBOL = 8;
- private static final int UNUM_INTL_CURRENCY_SYMBOL = 9;
- private static final int UNUM_MONETARY_SEPARATOR_SYMBOL = 10;
- private static final int UNUM_EXPONENTIAL_SYMBOL = 11;
- private static final int UNUM_PERMILL_SYMBOL = 12;
- private static final int UNUM_PAD_ESCAPE_SYMBOL = 13;
- private static final int UNUM_INFINITY_SYMBOL = 14;
- private static final int UNUM_NAN_SYMBOL = 15;
- private static final int UNUM_SIGNIFICANT_DIGIT_SYMBOL = 16;
- private static final int UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL = 17;
- private static final int UNUM_FORMAT_SYMBOL_COUNT = 18;
-
- private final int addr;
-
- // Used to implement clone.
- private DecimalFormatSymbols(DecimalFormatSymbols other) {
- this.addr = NativeDecimalFormat.cloneImpl(other.addr);
- }
-
- public DecimalFormatSymbols(Locale locale) {
- LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(locale);
- this.addr = NativeDecimalFormat.openDecimalFormatImpl(locale.toString(),
- localeData.numberPattern);
- NativeDecimalFormat.setSymbol(this.addr, UNUM_CURRENCY_SYMBOL, localeData.currencySymbol);
- NativeDecimalFormat.setSymbol(this.addr, UNUM_INTL_CURRENCY_SYMBOL,
- localeData.internationalCurrencySymbol);
- }
-
- public DecimalFormatSymbols(Locale locale, java.text.DecimalFormatSymbols symbols) {
- LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(locale);
- this.addr = NativeDecimalFormat.openDecimalFormatImpl(locale.toString(),
- localeData.numberPattern);
- copySymbols(symbols);
- }
-
- /**
- * Copies the java.text.DecimalFormatSymbols' settings into this object.
- */
- public void copySymbols(final java.text.DecimalFormatSymbols dfs) {
- setCurrencySymbol(dfs.getCurrencySymbol());
- setDecimalSeparator(dfs.getDecimalSeparator());
- setDigit(dfs.getDigit());
- setGroupingSeparator(dfs.getGroupingSeparator());
- setInfinity(dfs.getInfinity());
- setInternationalCurrencySymbol(dfs.getInternationalCurrencySymbol());
- setMinusSign(dfs.getMinusSign());
- setMonetaryDecimalSeparator(dfs.getMonetaryDecimalSeparator());
- setNaN(dfs.getNaN());
- setPatternSeparator(dfs.getPatternSeparator());
- setPercent(dfs.getPercent());
- setPerMill(dfs.getPerMill());
- setZeroDigit(dfs.getZeroDigit());
- }
-
- @Override
- public boolean equals(Object object) {
- if(object == null) {
- return false;
- }
- if(!(object instanceof DecimalFormatSymbols)) {
- return false;
- }
-
- DecimalFormatSymbols sym = (DecimalFormatSymbols) object;
-
- if(sym.addr == this.addr) {
- return true;
- }
-
- boolean result = true;
-
- Currency objCurr = sym.getCurrency();
- Currency thisCurr = this.getCurrency();
- if(objCurr != null) {
- result &= objCurr.getCurrencyCode().equals(thisCurr.getCurrencyCode());
- result &= objCurr.getSymbol().equals(thisCurr.getSymbol());
- result &= objCurr.getDefaultFractionDigits() == thisCurr.getDefaultFractionDigits();
- } else {
- result &= thisCurr == null;
- }
- result &= sym.getCurrencySymbol().equals(this.getCurrencySymbol());
- result &= sym.getDecimalSeparator() == this.getDecimalSeparator();
- result &= sym.getDigit() == this.getDigit();
- result &= sym.getGroupingSeparator() == this.getGroupingSeparator();
- result &= sym.getInfinity().equals(this.getInfinity());
- result &= sym.getInternationalCurrencySymbol().equals(
- this.getInternationalCurrencySymbol());
- result &= sym.getMinusSign() == this.getMinusSign();
- result &= sym.getMonetaryDecimalSeparator() ==
- this.getMonetaryDecimalSeparator();
- result &= sym.getNaN().equals(this.getNaN());
- result &= sym.getPatternSeparator() == this.getPatternSeparator();
- result &= sym.getPercent() == this.getPercent();
- result &= sym.getPerMill() == this.getPerMill();
- result &= sym.getZeroDigit() == this.getZeroDigit();
-
- return result;
- }
-
- @Override
- public Object clone() {
- return new DecimalFormatSymbols(this);
- }
-
- public void setCurrency(Currency currency) {
- NativeDecimalFormat.setSymbol(this.addr, UNUM_CURRENCY_SYMBOL, currency.getSymbol());
- NativeDecimalFormat.setSymbol(this.addr, UNUM_INTL_CURRENCY_SYMBOL,
- currency.getCurrencyCode());
- }
-
- public void setCurrencySymbol(String symbol) {
- NativeDecimalFormat.setSymbol(this.addr, UNUM_CURRENCY_SYMBOL, symbol);
- }
-
- public void setDecimalSeparator(char symbol) {
- NativeDecimalFormat.setSymbol(this.addr, UNUM_DECIMAL_SEPARATOR_SYMBOL, symbol);
- }
-
- public void setDigit(char symbol) {
- NativeDecimalFormat.setSymbol(this.addr, UNUM_DIGIT_SYMBOL, symbol);
- }
-
- public void setGroupingSeparator(char symbol) {
- NativeDecimalFormat.setSymbol(this.addr, UNUM_GROUPING_SEPARATOR_SYMBOL, symbol);
- NativeDecimalFormat.setSymbol(this.addr, UNUM_MONETARY_GROUPING_SEPARATOR_SYMBOL, symbol);
- }
-
- public void setInfinity(String symbol) {
- NativeDecimalFormat.setSymbol(this.addr, UNUM_INFINITY_SYMBOL, symbol);
- }
-
- public void setInternationalCurrencySymbol(String symbol) {
- NativeDecimalFormat.setSymbol(this.addr, UNUM_INTL_CURRENCY_SYMBOL, symbol);
- }
-
- public void setMinusSign(char symbol) {
- NativeDecimalFormat.setSymbol(this.addr, UNUM_MINUS_SIGN_SYMBOL, symbol);
- }
-
- public void setMonetaryDecimalSeparator(char symbol) {
- NativeDecimalFormat.setSymbol(this.addr, UNUM_MONETARY_SEPARATOR_SYMBOL, symbol);
- }
-
- public void setNaN(String symbol) {
- NativeDecimalFormat.setSymbol(this.addr, UNUM_NAN_SYMBOL, symbol);
- }
-
- public void setPatternSeparator(char symbol) {
- NativeDecimalFormat.setSymbol(this.addr, UNUM_PATTERN_SEPARATOR_SYMBOL, symbol);
- }
-
- public void setPercent(char symbol) {
- NativeDecimalFormat.setSymbol(this.addr, UNUM_PERCENT_SYMBOL, symbol);
- }
-
- public void setPerMill(char symbol) {
- NativeDecimalFormat.setSymbol(this.addr, UNUM_PERMILL_SYMBOL, symbol);
- }
-
- public void setZeroDigit(char symbol) {
- NativeDecimalFormat.setSymbol(this.addr, UNUM_ZERO_DIGIT_SYMBOL, symbol);
- }
-
- public Currency getCurrency() {
- String curr = NativeDecimalFormat.getSymbol(this.addr, UNUM_INTL_CURRENCY_SYMBOL);
- if (curr.equals("") || curr.equals("\u00a4\u00a4")) {
- return null;
- }
- return Currency.getInstance(curr);
- }
-
- public String getCurrencySymbol() {
- return NativeDecimalFormat.getSymbol(this.addr, UNUM_CURRENCY_SYMBOL);
- }
-
- public char getDecimalSeparator() {
- return NativeDecimalFormat.getSymbol(this.addr, UNUM_DECIMAL_SEPARATOR_SYMBOL).charAt(0);
- }
-
- public char getDigit() {
- return NativeDecimalFormat.getSymbol(this.addr, UNUM_DIGIT_SYMBOL).charAt(0);
- }
-
- public char getGroupingSeparator() {
- return NativeDecimalFormat.getSymbol(this.addr, UNUM_GROUPING_SEPARATOR_SYMBOL).charAt(0);
- }
-
- public String getInfinity() {
- return NativeDecimalFormat.getSymbol(this.addr, UNUM_INFINITY_SYMBOL);
- }
-
- public String getInternationalCurrencySymbol() {
- return NativeDecimalFormat.getSymbol(this.addr, UNUM_INTL_CURRENCY_SYMBOL);
- }
-
- public char getMinusSign() {
- return NativeDecimalFormat.getSymbol(this.addr, UNUM_MINUS_SIGN_SYMBOL).charAt(0);
- }
-
- public char getMonetaryDecimalSeparator() {
- return NativeDecimalFormat.getSymbol(this.addr, UNUM_MONETARY_SEPARATOR_SYMBOL).charAt(0);
- }
-
- public String getNaN() {
- return NativeDecimalFormat.getSymbol(this.addr, UNUM_NAN_SYMBOL);
- }
-
- public char getPatternSeparator() {
- return NativeDecimalFormat.getSymbol(this.addr, UNUM_PATTERN_SEPARATOR_SYMBOL).charAt(0);
- }
-
- public char getPercent() {
- return NativeDecimalFormat.getSymbol(this.addr, UNUM_PERCENT_SYMBOL).charAt(0);
- }
-
- public char getPerMill() {
- return NativeDecimalFormat.getSymbol(this.addr, UNUM_PERMILL_SYMBOL).charAt(0);
- }
-
- public char getZeroDigit() {
- return NativeDecimalFormat.getSymbol(this.addr, UNUM_ZERO_DIGIT_SYMBOL).charAt(0);
- }
-
- int getAddr() {
- return this.addr;
- }
-
- protected void finalize() {
- NativeDecimalFormat.closeDecimalFormatImpl(this.addr);
- }
-}
diff --git a/icu/src/main/java/com/ibm/icu4jni/text/NativeDecimalFormat.java b/icu/src/main/java/com/ibm/icu4jni/text/NativeDecimalFormat.java
index 88e0d5f..ec07fbd 100644
--- a/icu/src/main/java/com/ibm/icu4jni/text/NativeDecimalFormat.java
+++ b/icu/src/main/java/com/ibm/icu4jni/text/NativeDecimalFormat.java
@@ -55,15 +55,26 @@ final class NativeDecimalFormat {
UNUM_PUBLIC_RULESETS
}
- static native int openDecimalFormatImpl(String locale, String pattern);
+ static int openDecimalFormat(String locale, String pattern) {
+ try {
+ // FIXME: if we're about to override everything, should we just ask for the cheapest locale (presumably the root locale)?
+ return NativeDecimalFormat.openDecimalFormatImpl(locale, pattern);
+ } catch (NullPointerException npe) {
+ throw npe;
+ } catch (RuntimeException re) {
+ throw new IllegalArgumentException("syntax error: " + re.getMessage() + ": " + pattern);
+ }
+ }
+ private static native int openDecimalFormatImpl(String locale, String pattern);
static native void closeDecimalFormatImpl(int addr);
- static native int cloneImpl(int addr);
+ static native int cloneDecimalFormatImpl(int addr);
static native void setSymbol(int addr, int symbol, String str);
static native void setSymbol(int addr, int symbol, char ch);
+ // FIXME: do we need this any more? the Java-side object should be the canonical source.
static native String getSymbol(int addr, int symbol);
static native void setAttribute(int addr, int symbol, int i);
@@ -74,7 +85,16 @@ final class NativeDecimalFormat {
static native String getTextAttribute(int addr, int symbol);
- static native void applyPatternImpl(int addr, boolean localized, String pattern);
+ static void applyPattern(int addr, boolean localized, String pattern) {
+ try {
+ NativeDecimalFormat.applyPatternImpl(addr, localized, pattern);
+ } catch (NullPointerException npe) {
+ throw npe;
+ } catch (RuntimeException re) {
+ throw new IllegalArgumentException("syntax error: " + re.getMessage() + ": " + pattern);
+ }
+ }
+ private static native void applyPatternImpl(int addr, boolean localized, String pattern);
static native String toPatternImpl(int addr, boolean localized);
diff --git a/icu/src/main/native/NativeDecimalFormat.cpp b/icu/src/main/native/NativeDecimalFormat.cpp
index cde2001..e974521 100644
--- a/icu/src/main/native/NativeDecimalFormat.cpp
+++ b/icu/src/main/native/NativeDecimalFormat.cpp
@@ -14,8 +14,10 @@
* limitations under the License.
*/
+#define LOG_TAG "NativeDecimalFormat"
#include "JNIHelp.h"
#include "AndroidSystemNatives.h"
+#include "cutils/log.h"
#include "unicode/unum.h"
#include "unicode/numfmt.h"
#include "unicode/decimfmt.h"
@@ -26,14 +28,20 @@
#include <stdlib.h>
#include <string.h>
-#define LOG_TAG "NativeDecimalFormat"
-#include "cutils/log.h"
+// FIXME: move to JNIHelp.h
+static void jniThrowNullPointerException(JNIEnv* env) {
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
+}
-static jint openDecimalFormatImpl(JNIEnv *env, jclass clazz, jstring locale,
- jstring pattern) {
+DecimalFormat* toDecimalFormat(jint addr) {
+ return reinterpret_cast<DecimalFormat*>(static_cast<uintptr_t>(addr));
+}
- // the errorcode returned by unum_open
- UErrorCode status = U_ZERO_ERROR;
+static jint openDecimalFormatImpl(JNIEnv* env, jclass clazz, jstring locale, jstring pattern) {
+ if (pattern == NULL) {
+ jniThrowNullPointerException(env);
+ return 0;
+ }
// prepare the pattern string for the call to unum_open
const UChar *pattChars = env->GetStringChars(pattern, NULL);
@@ -43,6 +51,7 @@ static jint openDecimalFormatImpl(JNIEnv *env, jclass clazz, jstring locale,
const char *localeChars = env->GetStringUTFChars(locale, NULL);
// open a default type number format
+ UErrorCode status = U_ZERO_ERROR;
UNumberFormat *fmt = unum_open(UNUM_PATTERN_DECIMAL, pattChars, pattLen,
localeChars, NULL, &status);
@@ -50,13 +59,8 @@ static jint openDecimalFormatImpl(JNIEnv *env, jclass clazz, jstring locale,
env->ReleaseStringChars(pattern, pattChars);
env->ReleaseStringUTFChars(locale, localeChars);
- // check for an error
- if (icu4jni_error(env, status) != FALSE) {
- return 0;
- }
-
- // return the handle to the number format
- return (long) fmt;
+ icu4jni_error(env, status);
+ return static_cast<jint>(reinterpret_cast<uintptr_t>(fmt));
}
static void closeDecimalFormatImpl(JNIEnv *env, jclass clazz, jint addr) {
@@ -71,7 +75,7 @@ static void closeDecimalFormatImpl(JNIEnv *env, jclass clazz, jint addr) {
static void setSymbol(JNIEnv *env, uintptr_t addr, jint symbol,
const UChar* chars, int32_t charCount) {
UErrorCode status = U_ZERO_ERROR;
- UNumberFormat* fmt = reinterpret_cast<UNumberFormat*>(addr);
+ UNumberFormat* fmt = reinterpret_cast<UNumberFormat*>(static_cast<uintptr_t>(addr));
unum_setSymbol(fmt, static_cast<UNumberFormatSymbol>(symbol),
chars, charCount, &status);
icu4jni_error(env, status);
@@ -199,59 +203,29 @@ static jstring getTextAttribute(JNIEnv *env, jclass clazz, jint addr,
return res;
}
-static void applyPatternImpl(JNIEnv *env, jclass clazz, jint addr,
- jboolean localized, jstring pattern) {
-
- // the errorcode returned by unum_applyPattern
+static void applyPatternImpl(JNIEnv *env, jclass clazz, jint addr, jboolean localized, jstring pattern) {
+ if (pattern == NULL) {
+ jniThrowNullPointerException(env);
+ return;
+ }
+ UNumberFormat* fmt = reinterpret_cast<UNumberFormat*>(static_cast<uintptr_t>(addr));
+ const UChar* chars = env->GetStringChars(pattern, NULL);
+ jsize charCount = env->GetStringLength(pattern);
UErrorCode status = U_ZERO_ERROR;
-
- // get the pointer to the number format
- UNumberFormat *fmt = (UNumberFormat *)(int)addr;
-
- const UChar *pattChars = env->GetStringChars(pattern, NULL);
- int pattLen = env->GetStringLength(pattern);
-
- unum_applyPattern(fmt, localized, pattChars, pattLen, NULL, &status);
-
- env->ReleaseStringChars(pattern, pattChars);
-
+ unum_applyPattern(fmt, localized, chars, charCount, NULL, &status);
+ env->ReleaseStringChars(pattern, chars);
icu4jni_error(env, status);
}
-static jstring toPatternImpl(JNIEnv *env, jclass clazz, jint addr,
- jboolean localized) {
-
- uint32_t resultlength, reslenneeded;
-
- // the errorcode returned by unum_toPattern
- UErrorCode status = U_ZERO_ERROR;
-
- // get the pointer to the number format
- UNumberFormat *fmt = (UNumberFormat *)(int)addr;
-
- UChar* result = NULL;
- resultlength=0;
-
- // find out how long the result will be
- reslenneeded=unum_toPattern(fmt, localized, result, resultlength, &status);
-
- result = NULL;
- if(status==U_BUFFER_OVERFLOW_ERROR) {
- status=U_ZERO_ERROR;
- resultlength=reslenneeded+1;
- result=(UChar*)malloc(sizeof(UChar) * resultlength);
- reslenneeded=unum_toPattern(fmt, localized, result, resultlength,
- &status);
- }
- if (icu4jni_error(env, status) != FALSE) {
- return NULL;
+static jstring toPatternImpl(JNIEnv *env, jclass, jint addr, jboolean localized) {
+ DecimalFormat* fmt = toDecimalFormat(addr);
+ UnicodeString pattern;
+ if (localized) {
+ fmt->toLocalizedPattern(pattern);
+ } else {
+ fmt->toPattern(pattern);
}
-
- jstring res = env->NewString(result, reslenneeded);
-
- free(result);
-
- return res;
+ return env->NewString(pattern.getBuffer(), pattern.length());
}
template <typename T>
@@ -274,7 +248,7 @@ static jstring format(JNIEnv *env, jint addr, jobject field, jstring fieldType,
fp.setField(FieldPosition::DONT_CARE);
UnicodeString str;
- DecimalFormat* fmt = reinterpret_cast<DecimalFormat*>(static_cast<uintptr_t>(addr));
+ DecimalFormat* fmt = toDecimalFormat(addr);
fmt->format(val, str, fp, attrBufferPtr);
if (attrBufferPtr && strlen(attrBuffer.buffer) > 0) {
@@ -314,8 +288,7 @@ static jstring format(JNIEnv *env, jint addr, jobject field, jstring fieldType,
}
}
- const UChar* chars = str.getBuffer();
- jstring result = env->NewString(chars, str.length());
+ jstring result = env->NewString(str.getBuffer(), str.length());
delete[] attrBuffer.buffer;
return result;
}
@@ -362,7 +335,7 @@ static jstring formatDigitList(JNIEnv *env, jclass clazz, jint addr, jstring val
const char *digits = (isPositive ? valueChars : valueChars + 1);
int length = strlen(digits);
- DecimalFormat* fmt = reinterpret_cast<DecimalFormat*>(static_cast<uintptr_t>(addr));
+ DecimalFormat* fmt = toDecimalFormat(addr);
// The length of our digit list buffer must be the actual string length + 3,
// because ICU will append some additional characters at the head and at the
@@ -609,20 +582,9 @@ static jobject parse(JNIEnv *env, jclass clazz, jint addr, jstring text,
}
}
-static jint cloneImpl(JNIEnv *env, jclass clazz, jint addr) {
-
- UErrorCode status = U_ZERO_ERROR;
-
- UNumberFormat *fmt = (UNumberFormat *)(int)addr;
-
- UNumberFormat *result = unum_clone(fmt, &status);
-
- if(icu4jni_error(env, status) != FALSE) {
- return 0;
- }
-
- return (long) result;
-
+static jint cloneDecimalFormatImpl(JNIEnv *env, jclass, jint addr) {
+ DecimalFormat* fmt = toDecimalFormat(addr);
+ return static_cast<jint>(reinterpret_cast<uintptr_t>(fmt->clone()));
}
static JNINativeMethod gMethods[] = {
@@ -651,7 +613,7 @@ static JNINativeMethod gMethods[] = {
{"parse",
"(ILjava/lang/String;Ljava/text/ParsePosition;)Ljava/lang/Number;",
(void*) parse},
- {"cloneImpl", "(I)I", (void*) cloneImpl}
+ {"cloneDecimalFormatImpl", "(I)I", (void*) cloneDecimalFormatImpl}
};
int register_com_ibm_icu4jni_text_NativeDecimalFormat(JNIEnv* env) {
return jniRegisterNativeMethods(env,
diff --git a/icu/src/main/native/Resources.cpp b/icu/src/main/native/Resources.cpp
index 0df2859..00bf746 100644
--- a/icu/src/main/native/Resources.cpp
+++ b/icu/src/main/native/Resources.cpp
@@ -14,8 +14,10 @@
* limitations under the License.
*/
+#define LOG_TAG "Resources"
#include "JNIHelp.h"
#include "AndroidSystemNatives.h"
+#include "cutils/log.h"
#include "unicode/numfmt.h"
#include "unicode/locid.h"
#include "unicode/ucal.h"
@@ -37,9 +39,6 @@
#include <time.h>
#include <sys/time.h>
-#define LOG_TAG "Resources"
-#include "cutils/log.h"
-
static jclass string_class;
class ScopedResourceBundle {
diff --git a/luni/src/test/java/java/text/AllTests.java b/luni/src/test/java/java/text/AllTests.java
index 9d13a1a..4e96007 100644
--- a/luni/src/test/java/java/text/AllTests.java
+++ b/luni/src/test/java/java/text/AllTests.java
@@ -22,6 +22,7 @@ import junit.framework.TestSuite;
public class AllTests {
public static final Test suite() {
TestSuite suite = tests.TestSuiteFactory.createTestSuite();
+ suite.addTestSuite(java.text.DecimalFormatTest.class);
suite.addTestSuite(java.text.NumberFormatTest.class);
return suite;
}
diff --git a/luni/src/test/java/java/text/DecimalFormatTest.java b/luni/src/test/java/java/text/DecimalFormatTest.java
new file mode 100644
index 0000000..6b2eb3d
--- /dev/null
+++ b/luni/src/test/java/java/text/DecimalFormatTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package java.text;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import java.math.BigInteger;
+import java.util.Locale;
+
+public class DecimalFormatTest extends junit.framework.TestCase {
+ // Android fails this test, truncating to 127 digits.
+ public void test_setMaximumIntegerDigits() throws Exception {
+ NumberFormat numberFormat = NumberFormat.getNumberInstance(Locale.US);
+ numberFormat.setGroupingUsed(false);
+ numberFormat.setMinimumIntegerDigits(400);
+ // The RI's documentation suggests that the int should be formatted to 309 characters --
+ // a magic number they don't explain -- but the BigInteger should be formatted to the 400
+ // characters we asked for. In practice, the RI uses 309 in both cases.
+ assertEquals(309, numberFormat.format(123).length());
+ assertEquals(309, numberFormat.format(BigInteger.valueOf(123)).length());
+ }
+}
diff --git a/text/src/main/java/java/text/DecimalFormat.java b/text/src/main/java/java/text/DecimalFormat.java
index 3123e8c..b8bc41b 100644
--- a/text/src/main/java/java/text/DecimalFormat.java
+++ b/text/src/main/java/java/text/DecimalFormat.java
@@ -552,29 +552,17 @@ public class DecimalFormat extends NumberFormat {
private transient com.ibm.icu4jni.text.DecimalFormat dform;
- private transient com.ibm.icu4jni.text.DecimalFormatSymbols icuSymbols;
-
- private static final int CURRENT_SERIAL_VERTION = 3;
-
- private transient int serialVersionOnStream = 3;
-
/**
* Constructs a new {@code DecimalFormat} for formatting and parsing numbers
* for the default locale.
*/
public DecimalFormat() {
+ // BEGIN android-changed: reduce duplication.
Locale locale = Locale.getDefault();
- // BEGIN android-changed
- icuSymbols = new com.ibm.icu4jni.text.DecimalFormatSymbols(locale);
- symbols = new DecimalFormatSymbols(locale);
- LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(Locale.getDefault());
- dform = new com.ibm.icu4jni.text.DecimalFormat(localeData.numberPattern, icuSymbols);
+ this.symbols = new DecimalFormatSymbols(locale);
+ LocaleData localeData = com.ibm.icu4jni.util.Resources.getLocaleData(locale);
+ initNative(localeData.numberPattern, locale);
// END android-changed
-
- super.setMaximumFractionDigits(dform.getMaximumFractionDigits());
- super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits());
- super.setMinimumFractionDigits(dform.getMinimumFractionDigits());
- super.setMinimumIntegerDigits(dform.getMinimumIntegerDigits());
}
/**
@@ -587,17 +575,9 @@ public class DecimalFormat extends NumberFormat {
* if the pattern cannot be parsed.
*/
public DecimalFormat(String pattern) {
- Locale locale = Locale.getDefault();
- // BEGIN android-changed
- icuSymbols = new com.ibm.icu4jni.text.DecimalFormatSymbols(locale);
+ // BEGIN android-changed: reduce duplication.
+ this(pattern, Locale.getDefault());
// END android-changed
- symbols = new DecimalFormatSymbols(locale);
- dform = new com.ibm.icu4jni.text.DecimalFormat(pattern, icuSymbols);
-
- super.setMaximumFractionDigits(dform.getMaximumFractionDigits());
- super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits());
- super.setMinimumFractionDigits(dform.getMinimumFractionDigits());
- super.setMinimumIntegerDigits(dform.getMinimumIntegerDigits());
}
/**
@@ -612,25 +592,26 @@ public class DecimalFormat extends NumberFormat {
* if the pattern cannot be parsed.
*/
public DecimalFormat(String pattern, DecimalFormatSymbols value) {
- symbols = (DecimalFormatSymbols) value.clone();
- Locale locale = symbols.getLocale();
- // BEGIN android-changed
- icuSymbols = new com.ibm.icu4jni.text.DecimalFormatSymbols(locale, symbols);
+ // BEGIN android-changed: reduce duplication.
+ this.symbols = (DecimalFormatSymbols) value.clone();
+ initNative(pattern, symbols.getLocale());
// END android-changed
- dform = new com.ibm.icu4jni.text.DecimalFormat(pattern, icuSymbols);
-
- super.setMaximumFractionDigits(dform.getMaximumFractionDigits());
- super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits());
- super.setMinimumFractionDigits(dform.getMinimumFractionDigits());
- super.setMinimumIntegerDigits(dform.getMinimumIntegerDigits());
}
// BEGIN android-added: used by NumberFormat.getInstance because cloning DecimalFormatSymbols is slow.
DecimalFormat(String pattern, Locale locale) {
this.symbols = new DecimalFormatSymbols(locale);
- this.icuSymbols = new com.ibm.icu4jni.text.DecimalFormatSymbols(locale, symbols);
- this.dform = new com.ibm.icu4jni.text.DecimalFormat(pattern, icuSymbols);
+ initNative(pattern, locale);
+ }
+ // END android-added
+ // BEGIN android-changed: reduce duplication.
+ private void initNative(String pattern, Locale locale) {
+ try {
+ this.dform = new com.ibm.icu4jni.text.DecimalFormat(pattern, locale, symbols);
+ } catch (IllegalArgumentException ex) {
+ throw new IllegalArgumentException(pattern);
+ }
super.setMaximumFractionDigits(dform.getMaximumFractionDigits());
super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits());
super.setMinimumFractionDigits(dform.getMinimumFractionDigits());
@@ -638,19 +619,6 @@ public class DecimalFormat extends NumberFormat {
}
// END android-added
- // BEGIN android-removed
- // DecimalFormat(String pattern, DecimalFormatSymbols value, com.ibm.icu4jni.text.DecimalFormat icuFormat) {
- // symbols = value;
- // icuSymbols = value.getIcuSymbols();
- // dform = icuFormat;
- //
- // super.setMaximumFractionDigits(dform.getMaximumFractionDigits());
- // super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits());
- // super.setMinimumFractionDigits(dform.getMinimumFractionDigits());
- // super.setMinimumIntegerDigits(dform.getMinimumIntegerDigits());
- // }
- // END android-removed
-
/**
* Changes the pattern of this decimal format to the specified pattern which
* uses localized pattern characters.
@@ -674,7 +642,6 @@ public class DecimalFormat extends NumberFormat {
* if the pattern cannot be parsed.
*/
public void applyPattern(String pattern) {
-
dform.applyPattern(pattern);
}
@@ -712,9 +679,9 @@ public class DecimalFormat extends NumberFormat {
if (!(object instanceof DecimalFormat)) {
return false;
}
- DecimalFormat format = (DecimalFormat) object;
- return (this.dform == null ? format.dform == null : this.dform
- .equals(format.dform));
+ DecimalFormat other = (DecimalFormat) object;
+ return (this.dform == null ? other.dform == null : this.dform.equals(other.dform)) &&
+ getDecimalFormatSymbols().equals(other.getDecimalFormatSymbols());
}
/**
@@ -1058,10 +1025,10 @@ public class DecimalFormat extends NumberFormat {
*/
public void setDecimalFormatSymbols(DecimalFormatSymbols value) {
if (value != null) {
- symbols = (DecimalFormatSymbols) value.clone();
- icuSymbols = dform.getDecimalFormatSymbols();
- icuSymbols.copySymbols(symbols); // android-changed
- dform.setDecimalFormatSymbols(icuSymbols);
+ // BEGIN android-changed: the Java object is canonical, and we copy down to native code.
+ this.symbols = (DecimalFormatSymbols) value.clone();
+ dform.setDecimalFormatSymbols(this.symbols);
+ // END android-changed
}
}
@@ -1076,8 +1043,7 @@ public class DecimalFormat extends NumberFormat {
@Override
public void setCurrency(Currency currency) {
// BEGIN android-changed
- dform.setCurrency(Currency.getInstance(currency
- .getCurrencyCode()));
+ dform.setCurrency(Currency.getInstance(currency.getCurrencyCode()));
// END android-changed
symbols.setCurrency(currency);
}
@@ -1129,67 +1095,55 @@ public class DecimalFormat extends NumberFormat {
}
/**
- * Sets the maximum number of fraction digits that are printed when
- * formatting numbers other than {@code BigDecimal} and {@code BigInteger}.
- * If the maximum is less than the number of fraction digits, the least
- * significant digits are truncated. If the value passed is bigger than 340
- * then it is replaced by 340. If the value passed is negative then it is
- * replaced by 0.
+ * Sets the maximum number of digits after the decimal point.
+ * If the value passed is negative then it is replaced by 0.
+ * Regardless of this setting, no more than 340 digits will be used.
*
- * @param value
- * the maximum number of fraction digits.
+ * @param value the maximum number of fraction digits.
*/
@Override
public void setMaximumFractionDigits(int value) {
super.setMaximumFractionDigits(value);
- dform.setMaximumFractionDigits(value);
+ dform.setMaximumFractionDigits(getMaximumFractionDigits());
}
/**
- * Sets the maximum number of integer digits that are printed when
- * formatting numbers other than {@code BigDecimal} and {@code BigInteger}.
- * If the maximum is less than the number of integer digits, the most
- * significant digits are truncated. If the value passed is bigger than 309
- * then it is replaced by 309. If the value passed is negative then it is
- * replaced by 0.
+ * Sets the maximum number of digits before the decimal point.
+ * If the value passed is negative then it is replaced by 0.
+ * Regardless of this setting, no more than 309 digits will be used.
*
- * @param value
- * the maximum number of integer digits.
+ * @param value the maximum number of integer digits.
*/
@Override
public void setMaximumIntegerDigits(int value) {
super.setMaximumIntegerDigits(value);
- dform.setMaximumIntegerDigits(value);
+ dform.setMaximumIntegerDigits(getMaximumIntegerDigits());
}
/**
- * Sets the minimum number of fraction digits that are printed when
- * formatting numbers other than {@code BigDecimal} and {@code BigInteger}.
- * If the value passed is bigger than 340 then it is replaced by 340. If the
- * value passed is negative then it is replaced by 0.
+ * Sets the minimum number of digits after the decimal point.
+ * If the value passed is negative then it is replaced by 0.
+ * Regardless of this setting, no more than 340 digits will be used.
*
- * @param value
- * the minimum number of fraction digits.
+ * @param value the minimum number of fraction digits.
*/
@Override
public void setMinimumFractionDigits(int value) {
super.setMinimumFractionDigits(value);
- dform.setMinimumFractionDigits(value);
+ dform.setMinimumFractionDigits(getMinimumFractionDigits());
}
/**
- * Sets the minimum number of integer digits that are printed when
- * formatting numbers other than {@code BigDecimal} and {@code BigInteger}.
- * If the value passed is bigger than 309 then it is replaced by 309. If the
- * value passed is negative then it is replaced by 0.
+ * Sets the minimum number of digits before the decimal point.
+ * If the value passed is negative then it is replaced by 0.
+ * Regardless of this setting, no more than 309 digits will be used.
*
- * @param value
- * the minimum number of integer digits.
+ * @param value the minimum number of integer digits.
*/
@Override
public void setMinimumIntegerDigits(int value) {
super.setMinimumIntegerDigits(value);
- dform.setMinimumIntegerDigits(value);
+ dform.setMinimumIntegerDigits(getMinimumIntegerDigits());
}
/**
@@ -1340,17 +1294,13 @@ public class DecimalFormat extends NumberFormat {
.isDecimalSeparatorAlwaysShown());
fields.put("parseBigDecimal", parseBigDecimal);
fields.put("symbols", symbols);
- boolean useExponentialNotation = ((Boolean) Format.getInternalField(
- "useExponentialNotation", dform)).booleanValue();
- fields.put("useExponentialNotation", useExponentialNotation);
- byte minExponentDigits = ((Byte) Format.getInternalField(
- "minExponentDigits", dform)).byteValue();
- fields.put("minExponentDigits", minExponentDigits);
+ fields.put("useExponentialNotation", false);
+ fields.put("minExponentDigits", 0);
fields.put("maximumIntegerDigits", dform.getMaximumIntegerDigits());
fields.put("minimumIntegerDigits", dform.getMinimumIntegerDigits());
fields.put("maximumFractionDigits", dform.getMaximumFractionDigits());
fields.put("minimumFractionDigits", dform.getMinimumFractionDigits());
- fields.put("serialVersionOnStream", CURRENT_SERIAL_VERTION);
+ fields.put("serialVersionOnStream", 3);
stream.writeFields();
}
@@ -1390,26 +1340,17 @@ public class DecimalFormat extends NumberFormat {
boolean parseBigDecimal = fields.get("parseBigDecimal", false);
symbols = (DecimalFormatSymbols) fields.get("symbols", null);
- boolean useExponentialNotation = fields.get("useExponentialNotation",
- false);
- byte minExponentDigits = fields.get("minExponentDigits", (byte) 0);
-
int maximumIntegerDigits = fields.get("maximumIntegerDigits", 309);
int minimumIntegerDigits = fields.get("minimumIntegerDigits", 309);
int maximumFractionDigits = fields.get("maximumFractionDigits", 340);
int minimumFractionDigits = fields.get("minimumFractionDigits", 340);
- this.serialVersionOnStream = fields.get("serialVersionOnStream", 0);
+ int serialVersionOnStream = fields.get("serialVersionOnStream", 0);
Locale locale = (Locale) Format.getInternalField("locale", symbols);
// BEGIN android-changed
- icuSymbols = new com.ibm.icu4jni.text.DecimalFormatSymbols(locale, symbols);
- dform = new com.ibm.icu4jni.text.DecimalFormat("", //$NON-NLS-1$
- icuSymbols);
+ //this.dform = new com.ibm.icu4jni.text.DecimalFormat("", locale, symbols);
+ initNative("", locale);
// END android-changed
- setInternalField("useExponentialNotation", dform, Boolean
- .valueOf(useExponentialNotation));
- setInternalField("minExponentDigits", dform,
- new Byte(minExponentDigits));
dform.setPositivePrefix(positivePrefix);
dform.setPositiveSuffix(positiveSuffix);
dform.setNegativePrefix(negativePrefix);
@@ -1424,11 +1365,18 @@ public class DecimalFormat extends NumberFormat {
dform.setGroupingUsed(groupingUsed);
// END android-added
dform.setDecimalSeparatorAlwaysShown(decimalSeparatorAlwaysShown);
- dform.setMinimumIntegerDigits(minimumIntegerDigits);
+ setMinimumIntegerDigits(minimumIntegerDigits);
+ // BEGIN android-changed: tell ICU what we want, then ask it what we can have, and then
+ // set that in our Java object. This isn't RI-compatible, but then very little of our
+ // behavior in this area is, and it's not obvious how we can second-guess ICU (or tell
+ // it to just do exactly what we ask). We only need to do this with maximumIntegerDigits
+ // because ICU doesn't seem to have its own ideas about the other options.
dform.setMaximumIntegerDigits(maximumIntegerDigits);
- dform.setMinimumFractionDigits(minimumFractionDigits);
- dform.setMaximumFractionDigits(maximumFractionDigits);
- this.setParseBigDecimal(parseBigDecimal);
+ super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits());
+ // END android-changed
+ setMinimumFractionDigits(minimumFractionDigits);
+ setMaximumFractionDigits(maximumFractionDigits);
+ setParseBigDecimal(parseBigDecimal);
if (serialVersionOnStream < 3) {
setMaximumIntegerDigits(super.getMaximumIntegerDigits());
@@ -1436,11 +1384,6 @@ public class DecimalFormat extends NumberFormat {
setMaximumFractionDigits(super.getMaximumFractionDigits());
setMinimumFractionDigits(super.getMinimumFractionDigits());
}
- if (serialVersionOnStream < 1) {
- this.setInternalField("useExponentialNotation", dform,
- Boolean.FALSE);
- }
- serialVersionOnStream = 3;
}
/*
diff --git a/text/src/main/java/java/text/DecimalFormatSymbols.java b/text/src/main/java/java/text/DecimalFormatSymbols.java
index 1a35d0a..6d1dcde 100644
--- a/text/src/main/java/java/text/DecimalFormatSymbols.java
+++ b/text/src/main/java/java/text/DecimalFormatSymbols.java
@@ -15,10 +15,6 @@
* limitations under the License.
*/
-// BEGIN android-note
-// changed from ICU to resource bundles
-// END android-note
-
package java.text;
import java.io.IOException;
@@ -29,9 +25,6 @@ import java.io.Serializable;
import java.util.Arrays;
import java.util.Currency;
import java.util.Locale;
-// BEGIN android-added
-import java.util.ResourceBundle;
-// END android-added
import com.ibm.icu4jni.util.LocaleData;
@@ -557,10 +550,4 @@ public final class DecimalFormatSymbols implements Cloneable, Serializable {
Locale getLocale(){
return locale;
}
-
- // BEGIN android-removed
- // com.ibm.icu4jni.text.DecimalFormatSymbols getIcuSymbols() {
- // return icuSymbols;
- // }
- // END android-removed
}
diff --git a/text/src/test/java/org/apache/harmony/text/tests/java/text/DecimalFormatTest.java b/text/src/test/java/org/apache/harmony/text/tests/java/text/DecimalFormatTest.java
index ef70bf2..ec8c9a2 100644
--- a/text/src/test/java/org/apache/harmony/text/tests/java/text/DecimalFormatTest.java
+++ b/text/src/test/java/org/apache/harmony/text/tests/java/text/DecimalFormatTest.java
@@ -1270,7 +1270,7 @@ public class DecimalFormatTest extends TestCase {
try {
new DecimalFormat(null);
- fail("NullPointerException was thrown.");
+ fail("NullPointerException wasn't thrown.");
} catch(NullPointerException npe){
//expected
}
@@ -1279,7 +1279,7 @@ public class DecimalFormatTest extends TestCase {
for(String str:incPatterns) {
try {
new DecimalFormat(str);
- fail("NullPointerException was thrown for pattern: " + str);
+ fail("IllegalArgumentException wasn't thrown for pattern: " + str);
} catch(IllegalArgumentException iae){
//expected
}