8196399: Formatting a decimal using locale-specific grouping separators causes ArithmeticException (division by zero).
8199672: ClassCastException is thrown by java.util.Formatter when an NumberFormatProvider SPI is used.
Reviewed-by: naoto
--- a/src/java.base/share/classes/java/util/Formatter.java Thu Mar 22 08:09:51 2018 +0800
+++ b/src/java.base/share/classes/java/util/Formatter.java Thu Mar 22 12:59:58 2018 +0530
@@ -47,6 +47,7 @@
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
+import java.text.spi.NumberFormatProvider;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.Objects;
@@ -62,6 +63,8 @@
import jdk.internal.math.DoubleConsts;
import jdk.internal.math.FormattedFloatingDecimal;
+import sun.util.locale.provider.LocaleProviderAdapter;
+import sun.util.locale.provider.ResourceBundleBasedAdapter;
/**
* An interpreter for printf-style format strings. This class provides support
@@ -4476,8 +4479,33 @@
} else {
DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(l);
grpSep = dfs.getGroupingSeparator();
- DecimalFormat df = (DecimalFormat) NumberFormat.getIntegerInstance(l);
+ DecimalFormat df = null;
+ NumberFormat nf = NumberFormat.getNumberInstance(l);
+ if (nf instanceof DecimalFormat) {
+ df = (DecimalFormat) nf;
+ } else {
+
+ // Use DecimalFormat constructor to obtain the instance,
+ // in case NumberFormat.getNumberInstance(l)
+ // returns instance other than DecimalFormat
+ LocaleProviderAdapter adapter = LocaleProviderAdapter
+ .getAdapter(NumberFormatProvider.class, l);
+ if (!(adapter instanceof ResourceBundleBasedAdapter)) {
+ adapter = LocaleProviderAdapter.getResourceBundleBased();
+ }
+ String[] all = adapter.getLocaleResources(l)
+ .getNumberPatterns();
+ df = new DecimalFormat(all[0], dfs);
+ }
grpSize = df.getGroupingSize();
+ // Some locales do not use grouping (the number
+ // pattern for these locales does not contain group, e.g.
+ // ("#0.###")), but specify a grouping separator.
+ // To avoid unnecessary identification of the position of
+ // grouping separator, reset its value with null character
+ if (!df.isGroupingUsed() || grpSize == 0) {
+ grpSep = '\0';
+ }
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/util/Formatter/NoGroupingUsed.java Thu Mar 22 12:59:58 2018 +0530
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * @test
+ * @bug 8196399
+ * @summary test Formatter if any ArithmeticException is thrown while
+ * formatting a number in the locale which does not use any
+ * grouping, but specifies a grouping separator e.g. hy_AM.
+ * @modules jdk.localedata
+ */
+import java.util.Formatter;
+import java.util.Locale;
+
+public class NoGroupingUsed {
+
+ public static void main(String[] args) {
+
+ Locale locale = new Locale("hy", "AM");
+ String number = "1234567";
+ String formatString = "%,d";
+
+ try {
+ testGrouping(locale, formatString, number);
+ } catch (ArithmeticException ex) {
+ throw new RuntimeException("[FAILED: ArithmeticException occurred"
+ + " while formatting the number: " + number + ", with"
+ + " format string: " + formatString + ", in locale: "
+ + locale, ex);
+ }
+
+ }
+
+ private static void testGrouping(Locale locale, String formatString, String number) {
+
+ // test using String.format
+ String result = String.format(locale, formatString, Integer.parseInt(number));
+ if (!number.equals(result)) {
+ throw new RuntimeException("[FAILED: Incorrect formatting"
+ + " of number: " + number + " using String.format with format"
+ + " string: " + formatString + " in locale: " + locale
+ + ". Actual: " + result + ", Expected: " + number + "]");
+ }
+
+ // test using Formatter's format
+ StringBuilder sb = new StringBuilder();
+ Formatter formatter = new Formatter(sb, locale);
+ formatter.format(formatString, Integer.parseInt(number));
+ if (!number.equals(sb.toString())) {
+ throw new RuntimeException("[FAILED: Incorrect formatting"
+ + " of number: " + number + "using Formatter.format with"
+ + " format string: " + formatString + " in locale: " + locale
+ + ". Actual: " + sb.toString() + ", Expected: " + number + "]");
+ }
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/util/Formatter/spi/FormatterWithProvider.java Thu Mar 22 12:59:58 2018 +0530
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+/*
+ * @test
+ * @bug 8199672
+ * @summary test the Formatter.format() method with java.locale.providers=SPI,
+ * COMPAT. It should not throw ClassCastException if an SPI is
+ * used and NumberFormat.getInstance() does not return a
+ * DecimalFormat object.
+ * @modules jdk.localedata
+ * @library provider
+ * @build provider/module-info provider/test.NumberFormatProviderImpl
+ * @run main/othervm -Djava.locale.providers=SPI,COMPAT FormatterWithProvider
+ */
+
+import java.util.Formatter;
+import java.util.Locale;
+
+public class FormatterWithProvider {
+
+ public static void main(String[] args) {
+
+ Integer number = 1234567;
+ String formatString = "%,d";
+
+ try {
+ testFormatter(Locale.JAPANESE, formatString, number);
+ testFormatter(Locale.FRENCH, formatString, number);
+ testFormatter(new Locale("hi", "IN"), formatString, number);
+
+ } catch (ClassCastException ex) {
+ throw new RuntimeException("[FAILED: A ClassCastException is" +
+ " thrown while using Formatter.format() with VM" +
+ " argument java.locale.providers=SPI,COMPAT]", ex);
+ }
+ }
+
+ private static void testFormatter(Locale locale, String formatString,
+ Integer number) {
+
+ // test using String.format
+ String.format(locale, formatString, number);
+ // test using Formatter's format
+ Formatter formatter = new Formatter(locale);
+ formatter.format(formatString, number);
+ }
+
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/util/Formatter/spi/provider/module-info.java Thu Mar 22 12:59:58 2018 +0530
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+*/
+module provider {
+ exports test;
+ provides java.text.spi.NumberFormatProvider with test.NumberFormatProviderImpl;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/util/Formatter/spi/provider/test/NumberFormatProviderImpl.java Thu Mar 22 12:59:58 2018 +0530
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package test;
+
+import java.text.FieldPosition;
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+import java.text.spi.NumberFormatProvider;
+import java.util.Locale;
+
+public class NumberFormatProviderImpl extends NumberFormatProvider {
+
+ private static final Locale[] locales = {Locale.FRENCH, Locale.JAPANESE,
+ new Locale("hi", "IN")};
+
+ @Override
+ public NumberFormat getCurrencyInstance(Locale locale) {
+ return null;
+ }
+
+ @Override
+ public NumberFormat getIntegerInstance(Locale locale) {
+ return null;
+ }
+
+ @Override
+ public NumberFormat getNumberInstance(Locale locale) {
+ return null;
+ }
+
+ @Override
+ public NumberFormat getPercentInstance(Locale locale) {
+ return null;
+ }
+
+ @Override
+ public Locale[] getAvailableLocales() {
+ return locales;
+ }
+}
+