Merge "Fix NumberFormat's behavior with BigInteger and custom Number subclasses."
diff --git a/libcore/icu/src/main/java/com/ibm/icu4jni/text/NativeDecimalFormat.java b/libcore/icu/src/main/java/com/ibm/icu4jni/text/NativeDecimalFormat.java
index fd22ed0..c8fc252 100644
--- a/libcore/icu/src/main/java/com/ibm/icu4jni/text/NativeDecimalFormat.java
+++ b/libcore/icu/src/main/java/com/ibm/icu4jni/text/NativeDecimalFormat.java
@@ -218,7 +218,32 @@
// Get new value by multiplying multiplier.
return valBigDecimal.multiply(multiplierBigDecimal);
}
-
+
+ public StringBuffer formatBigDecimal(BigDecimal value, StringBuffer buffer, FieldPosition field) {
+ if (buffer == null || field == null) {
+ throw new NullPointerException();
+ }
+ if (getMultiplier() != 1) {
+ value = applyMultiplier(value);
+ }
+ StringBuilder val = new StringBuilder();
+ val.append(value.unscaledValue().toString(10));
+ int scale = value.scale();
+ scale = makeScalePositive(scale, val);
+ String fieldType = getFieldType(field.getFieldAttribute());
+ String result = format(this.addr, val.toString(), field, fieldType, null, scale);
+ return buffer.append(result);
+ }
+
+ public StringBuffer formatBigInteger(BigInteger value, StringBuffer buffer, FieldPosition field) {
+ if (buffer == null || field == null) {
+ throw new NullPointerException();
+ }
+ String fieldType = getFieldType(field.getFieldAttribute());
+ String result = format(this.addr, value.toString(10), field, fieldType, null, 0);
+ return buffer.append(result);
+ }
+ /*
public StringBuffer format(Object value, StringBuffer buffer, FieldPosition field) {
if (!(value instanceof Number)) {
throw new IllegalArgumentException();
@@ -228,21 +253,6 @@
}
String fieldType = getFieldType(field.getFieldAttribute());
Number number = (Number) value;
- if (number instanceof BigInteger) {
- BigInteger valBigInteger = (BigInteger) number;
- String result = format(this.addr, valBigInteger.toString(10), field, fieldType, null, 0);
- return buffer.append(result);
- } else if (number instanceof BigDecimal) {
- BigDecimal valBigDecimal = (BigDecimal) number;
- if (getMultiplier() != 1) {
- valBigDecimal = applyMultiplier(valBigDecimal);
- }
- StringBuilder val = new StringBuilder();
- val.append(valBigDecimal.unscaledValue().toString(10));
- int scale = valBigDecimal.scale();
- scale = makeScalePositive(scale, val);
- String result = format(this.addr, val.toString(), field, fieldType, null, scale);
- return buffer.append(result);
} else if (number instanceof Double || number instanceof Float) {
double dv = number.doubleValue();
String result = format(this.addr, dv, field, fieldType, null);
@@ -253,7 +263,7 @@
return buffer.append(result);
}
}
-
+*/
public StringBuffer format(long value, StringBuffer buffer, FieldPosition field) {
if (buffer == null || field == null) {
throw new NullPointerException();
diff --git a/libcore/luni/src/test/java/java/text/NumberFormatTest.java b/libcore/luni/src/test/java/java/text/NumberFormatTest.java
index 3626a44..66e1759 100644
--- a/libcore/luni/src/test/java/java/text/NumberFormatTest.java
+++ b/libcore/luni/src/test/java/java/text/NumberFormatTest.java
@@ -19,9 +19,49 @@
import junit.framework.Test;
import junit.framework.TestSuite;
+import java.math.BigInteger;
import java.util.Locale;
public class NumberFormatTest extends junit.framework.TestCase {
+ // NumberFormat.format(Object, StringBuffer, FieldPosition) guarantees it calls doubleValue for
+ // custom Number subclasses.
+ public void test_custom_Number_gets_longValue() throws Exception {
+ class MyNumber extends Number {
+ public byte byteValue() { throw new UnsupportedOperationException(); }
+ public double doubleValue() { return 123; }
+ public float floatValue() { throw new UnsupportedOperationException(); }
+ public int intValue() { throw new UnsupportedOperationException(); }
+ public long longValue() { throw new UnsupportedOperationException(); }
+ public short shortValue() { throw new UnsupportedOperationException(); }
+ public String toString() { throw new UnsupportedOperationException(); }
+ }
+ NumberFormat nf = NumberFormat.getNumberInstance(Locale.US);
+ assertEquals("123", nf.format(new MyNumber()));
+ }
+
+ // NumberFormat.format(Object, StringBuffer, FieldPosition) guarantees it calls longValue for
+ // any BigInteger with a bitLength strictly less than 64.
+ public void test_small_BigInteger_gets_longValue() throws Exception {
+ class MyNumberFormat extends NumberFormat {
+ public StringBuffer format(double value, StringBuffer b, FieldPosition f) {
+ b.append("double");
+ return b;
+ }
+ public StringBuffer format(long value, StringBuffer b, FieldPosition f) {
+ b.append("long");
+ return b;
+ }
+ public Number parse(String string, ParsePosition p) {
+ throw new UnsupportedOperationException();
+ }
+ }
+ NumberFormat nf = new MyNumberFormat();
+ assertEquals("long", nf.format(BigInteger.valueOf(Long.MAX_VALUE)));
+ assertEquals("double", nf.format(BigInteger.valueOf(Long.MAX_VALUE).add(BigInteger.ONE)));
+ assertEquals("long", nf.format(BigInteger.valueOf(Long.MIN_VALUE)));
+ assertEquals("double", nf.format(BigInteger.valueOf(Long.MIN_VALUE).subtract(BigInteger.ONE)));
+ }
+
public void test_getIntegerInstance_ar() throws Exception {
NumberFormat numberFormat = NumberFormat.getNumberInstance(new Locale("ar"));
assertEquals("#,##0.###;#,##0.###-", ((DecimalFormat) numberFormat).toPattern());
diff --git a/libcore/text/src/main/java/java/text/DateFormat.java b/libcore/text/src/main/java/java/text/DateFormat.java
index 8c9ded5..bf7ebbe 100644
--- a/libcore/text/src/main/java/java/text/DateFormat.java
+++ b/libcore/text/src/main/java/java/text/DateFormat.java
@@ -26,9 +26,6 @@
import java.util.Date;
import java.util.Hashtable;
import java.util.Locale;
-// BEGIN android-added
-import java.util.ResourceBundle;
-// BEGIN android-added
import java.util.TimeZone;
import com.ibm.icu4jni.util.LocaleData;
diff --git a/libcore/text/src/main/java/java/text/DateFormatSymbols.java b/libcore/text/src/main/java/java/text/DateFormatSymbols.java
index 184cdcf..ac23ad2 100644
--- a/libcore/text/src/main/java/java/text/DateFormatSymbols.java
+++ b/libcore/text/src/main/java/java/text/DateFormatSymbols.java
@@ -26,9 +26,6 @@
import java.io.Serializable;
import java.util.Arrays;
import java.util.Locale;
-// BEGIN android-added
-import java.util.ResourceBundle;
-// END android-added
// BEGIN android-added
import com.ibm.icu4jni.util.LocaleData;
diff --git a/libcore/text/src/main/java/java/text/DecimalFormat.java b/libcore/text/src/main/java/java/text/DecimalFormat.java
index 0991adb..8d5d022 100644
--- a/libcore/text/src/main/java/java/text/DecimalFormat.java
+++ b/libcore/text/src/main/java/java/text/DecimalFormat.java
@@ -707,89 +707,27 @@
return dform.formatToCharacterIterator(object);
}
- /**
- * Formats the specified double value as a string using the pattern of this
- * decimal format and appends the string to the specified string buffer.
- * <p>
- * If the {@code field} member of {@code position} contains a value
- * specifying a format field, then its {@code beginIndex} and
- * {@code endIndex} members will be updated with the position of the first
- * occurrence of this field in the formatted text.
- *
- * @param value
- * the double to format.
- * @param buffer
- * the target string buffer to append the formatted double value
- * to.
- * @param position
- * on input: an optional alignment field; on output: the offsets
- * of the alignment field in the formatted text.
- * @return the string buffer.
- */
@Override
- public StringBuffer format(double value, StringBuffer buffer,
- FieldPosition position) {
+ public StringBuffer format(double value, StringBuffer buffer, FieldPosition position) {
return dform.format(value, buffer, position);
}
- /**
- * Formats the specified long value as a string using the pattern of this
- * decimal format and appends the string to the specified string buffer.
- * <p>
- * If the {@code field} member of {@code position} contains a value
- * specifying a format field, then its {@code beginIndex} and
- * {@code endIndex} members will be updated with the position of the first
- * occurrence of this field in the formatted text.
- *
- * @param value
- * the long to format.
- * @param buffer
- * the target string buffer to append the formatted long value
- * to.
- * @param position
- * on input: an optional alignment field; on output: the offsets
- * of the alignment field in the formatted text.
- * @return the string buffer.
- */
@Override
- public StringBuffer format(long value, StringBuffer buffer,
- FieldPosition position) {
+ public StringBuffer format(long value, StringBuffer buffer, FieldPosition position) {
return dform.format(value, buffer, position);
}
- /**
- * Formats the specified object as a string using the pattern of this
- * decimal format and appends the string to the specified string buffer.
- * <p>
- * If the {@code field} member of {@code position} contains a value
- * specifying a format field, then its {@code beginIndex} and
- * {@code endIndex} members will be updated with the position of the first
- * occurrence of this field in the formatted text.
- *
- * @param number
- * the object to format.
- * @param toAppendTo
- * the target string buffer to append the formatted number to.
- * @param pos
- * on input: an optional alignment field; on output: the offsets
- * of the alignment field in the formatted text.
- * @return the string buffer.
- * @throws IllegalArgumentException
- * if {@code number} is not an instance of {@code Number}.
- * @throws NullPointerException
- * if {@code toAppendTo} or {@code pos} is {@code null}.
- */
@Override
- public final StringBuffer format(Object number, StringBuffer toAppendTo,
- FieldPosition pos) {
- if (!(number instanceof Number)) {
- throw new IllegalArgumentException();
- }
- if (toAppendTo == null || pos == null) {
- throw new NullPointerException();
- }
- if (number instanceof BigInteger || number instanceof BigDecimal) {
- return dform.format(number, toAppendTo, pos);
+ public final StringBuffer format(Object number, StringBuffer toAppendTo, FieldPosition pos) {
+ if (number instanceof BigInteger) {
+ BigInteger bigInteger = (BigInteger) number;
+ if (bigInteger.bitLength() < 64) {
+ return dform.format(bigInteger.longValue(), toAppendTo, pos);
+ } else {
+ return dform.formatBigInteger(bigInteger, toAppendTo, pos);
+ }
+ } else if (number instanceof BigDecimal) {
+ return dform.formatBigDecimal((BigDecimal) number, toAppendTo, pos);
}
return super.format(number, toAppendTo, pos);
}
diff --git a/libcore/text/src/main/java/java/text/Format.java b/libcore/text/src/main/java/java/text/Format.java
index eb1b837..567b0f6 100644
--- a/libcore/text/src/main/java/java/text/Format.java
+++ b/libcore/text/src/main/java/java/text/Format.java
@@ -22,7 +22,6 @@
import java.security.PrivilegedAction;
// BEGIN android-added
import java.util.Locale;
-import java.util.ResourceBundle;
// END android-added
import org.apache.harmony.text.internal.nls.Messages;
diff --git a/libcore/text/src/main/java/java/text/NumberFormat.java b/libcore/text/src/main/java/java/text/NumberFormat.java
index 5f6693d..0ad6ac4 100644
--- a/libcore/text/src/main/java/java/text/NumberFormat.java
+++ b/libcore/text/src/main/java/java/text/NumberFormat.java
@@ -26,11 +26,9 @@
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamField;
+import java.math.BigInteger;
import java.util.Currency;
import java.util.Locale;
-// BEGIN android-added
-import java.util.ResourceBundle;
-// END android-added
import com.ibm.icu4jni.util.LocaleData;
import org.apache.harmony.text.internal.nls.Messages;
@@ -242,8 +240,7 @@
* of the alignment field in the formatted text.
* @return the string buffer.
*/
- public abstract StringBuffer format(double value, StringBuffer buffer,
- FieldPosition field);
+ public abstract StringBuffer format(double value, StringBuffer buffer, FieldPosition field);
/**
* Formats the specified long using the rules of this number format.
@@ -276,12 +273,15 @@
* of the alignment field in the formatted text.
* @return the string buffer.
*/
- public abstract StringBuffer format(long value, StringBuffer buffer,
- FieldPosition field);
+ public abstract StringBuffer format(long value, StringBuffer buffer, FieldPosition field);
/**
- * Formats the specified object as a string using the pattern of this number
- * format and appends the string to the specified string buffer.
+ * Formats a number into a supplied buffer.
+ * <p>
+ * The number must be a subclass of {@code Number}. Instances of {@code Byte}, {@code Short},
+ * {@code Integer}, and {@code Long} have {@code Number.longValue} invoked, as do instances of
+ * {@code BigInteger} where {@code BigInteger.bitLength} returns <i>less than</i> 64. All other
+ * values have {@code Number.doubleValue} invoked instead.
* <p>
* If the {@code field} member of {@code field} contains a value specifying
* a format field, then its {@code beginIndex} and {@code endIndex} members
@@ -300,14 +300,15 @@
* if {@code object} is not an instance of {@code Number}.
*/
@Override
- public StringBuffer format(Object object, StringBuffer buffer,
- FieldPosition field) {
- if (object instanceof Double || object instanceof Float) {
- double dv = ((Number) object).doubleValue();
- return format(dv, buffer, field);
- } else if (object instanceof Number) {
+ public StringBuffer format(Object object, StringBuffer buffer, FieldPosition field) {
+ if (object instanceof Byte || object instanceof Short || object instanceof Integer ||
+ object instanceof Long ||
+ (object instanceof BigInteger && ((BigInteger) object).bitLength() < 64)) {
long lv = ((Number) object).longValue();
return format(lv, buffer, field);
+ } else if (object instanceof Number) {
+ double dv = ((Number) object).doubleValue();
+ return format(dv, buffer, field);
}
throw new IllegalArgumentException();
}
diff --git a/libcore/text/src/main/java/java/text/SimpleDateFormat.java b/libcore/text/src/main/java/java/text/SimpleDateFormat.java
index e2422ad..a67c7e6 100644
--- a/libcore/text/src/main/java/java/text/SimpleDateFormat.java
+++ b/libcore/text/src/main/java/java/text/SimpleDateFormat.java
@@ -1040,7 +1040,6 @@
* @return the {@code DateFormatSymbols} object.
*/
public DateFormatSymbols getDateFormatSymbols() {
- // Return a clone so the arrays in the ResourceBundle are not modified
return (DateFormatSymbols) formatData.clone();
}