# HG changeset patch # User nishjain # Date 1513149218 -19800 # Node ID 1925dbd47e28535ec2af6fc8b603bbffb80b4846 # Parent 125716343184aa11314c064687028a055981b2d6 8190278: ClassCastException is thrown by java.util.Scanner when a NumberFormatProvider is used. Reviewed-by: naoto, rriggs Contributed-by: nishit.jain@oracle.com diff -r 125716343184 -r 1925dbd47e28 src/java.base/share/classes/java/util/Scanner.java --- a/src/java.base/share/classes/java/util/Scanner.java Tue Dec 12 20:18:14 2017 -0800 +++ b/src/java.base/share/classes/java/util/Scanner.java Wed Dec 13 12:43:38 2017 +0530 @@ -33,10 +33,13 @@ import java.nio.file.Path; import java.nio.file.Files; import java.text.*; +import java.text.spi.NumberFormatProvider; import java.util.function.Consumer; import java.util.regex.*; import java.util.stream.Stream; import java.util.stream.StreamSupport; +import sun.util.locale.provider.LocaleProviderAdapter; +import sun.util.locale.provider.ResourceBundleBasedAdapter; /** * A simple text scanner which can parse primitive types and strings using @@ -1262,9 +1265,27 @@ modCount++; this.locale = locale; - DecimalFormat df = - (DecimalFormat)NumberFormat.getNumberInstance(locale); + + DecimalFormat df = null; + NumberFormat nf = NumberFormat.getNumberInstance(locale); DecimalFormatSymbols dfs = DecimalFormatSymbols.getInstance(locale); + if (nf instanceof DecimalFormat) { + df = (DecimalFormat) nf; + } else { + + // In case where NumberFormat.getNumberInstance() returns + // other instance (non DecimalFormat) based on the provider + // used and java.text.spi.NumberFormatProvider implementations, + // DecimalFormat constructor is used to obtain the instance + LocaleProviderAdapter adapter = LocaleProviderAdapter + .getAdapter(NumberFormatProvider.class, locale); + if (!(adapter instanceof ResourceBundleBasedAdapter)) { + adapter = LocaleProviderAdapter.getResourceBundleBased(); + } + String[] all = adapter.getLocaleResources(locale) + .getNumberPatterns(); + df = new DecimalFormat(all[0], dfs); + } // These must be literalized to avoid collision with regex // metacharacters such as dot or parenthesis diff -r 125716343184 -r 1925dbd47e28 test/jdk/java/util/Scanner/spi/UseLocaleWithProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/util/Scanner/spi/UseLocaleWithProvider.java Wed Dec 13 12:43:38 2017 +0530 @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2017, 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 8190278 + * @summary checks the Scanner.useLocale() with java.locale.providers=SPI, + * COMPAT. It should not throw ClassCastException if any SPI is + * used and NumberFormat.getInstance() does not return a + * DecimalFormat object. Also, to test the behaviour of Scanner + * while scanning numbers in the format of Scanner's locale. + * @modules jdk.localedata + * @library provider + * @build provider/module-info provider/test.NumberFormatProviderImpl + * provider/test.NumberFormatImpl + * @run main/othervm -Djava.locale.providers=SPI,COMPAT UseLocaleWithProvider + */ + +import java.util.Locale; +import java.util.Scanner; + +public class UseLocaleWithProvider { + + public static void main(String[] args) { + + try { + testScannerUseLocale("-123.4", Locale.US, -123.4); + testScannerUseLocale("-123,45", new Locale("fi", "FI"), -123.45); + testScannerUseLocale("334,65", Locale.FRENCH, 334.65); + testScannerUseLocale("4.334,65", Locale.GERMAN, 4334.65); + } catch (ClassCastException ex) { + throw new RuntimeException("[FAILED: With" + + " java.locale.providers=SPI,COMPAT, Scanner.useLocale()" + + " shouldn't throw ClassCastException]"); + } + } + + private static void testScannerUseLocale(String number, Locale locale, + Number actual) { + Scanner sc = new Scanner(number).useLocale(locale); + if (!sc.hasNextFloat() || sc.nextFloat() != actual.floatValue()) { + throw new RuntimeException("[FAILED: With" + + " java.locale.providers=SPI,COMPAT, Scanner" + + ".hasNextFloat() or Scanner.nextFloat() is unable to" + + " scan the given number: " + number + ", in the given" + + " locale:" + locale + "]"); + } + } +} + diff -r 125716343184 -r 1925dbd47e28 test/jdk/java/util/Scanner/spi/provider/module-info.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/util/Scanner/spi/provider/module-info.java Wed Dec 13 12:43:38 2017 +0530 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2017, 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; +} diff -r 125716343184 -r 1925dbd47e28 test/jdk/java/util/Scanner/spi/provider/test/NumberFormatImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/util/Scanner/spi/provider/test/NumberFormatImpl.java Wed Dec 13 12:43:38 2017 +0530 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2017, 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; + +public class NumberFormatImpl extends NumberFormat { + + @Override + public StringBuffer format(double number, StringBuffer toAppendTo, + FieldPosition pos) { + return null; + } + + @Override + public StringBuffer format(long number, StringBuffer toAppendTo, + FieldPosition pos) { + return null; + } + + @Override + public Number parse(String source, ParsePosition parsePosition) { + return null; + } +} + diff -r 125716343184 -r 1925dbd47e28 test/jdk/java/util/Scanner/spi/provider/test/NumberFormatProviderImpl.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/jdk/java/util/Scanner/spi/provider/test/NumberFormatProviderImpl.java Wed Dec 13 12:43:38 2017 +0530 @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017, 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.NumberFormat; +import java.text.spi.NumberFormatProvider; +import java.util.Locale; + +public class NumberFormatProviderImpl extends NumberFormatProvider { + + private static final Locale[] locales = {Locale.US, Locale.FRENCH, + Locale.GERMAN, new Locale("fi", "FI")}; + + @Override + public NumberFormat getCurrencyInstance(Locale locale) { + return null; + } + + @Override + public NumberFormat getIntegerInstance(Locale locale) { + return null; + } + + @Override + public NumberFormat getNumberInstance(Locale locale) { + return new NumberFormatImpl(); + } + + @Override + public NumberFormat getPercentInstance(Locale locale) { + return null; + } + + @Override + public Locale[] getAvailableLocales() { + return locales; + } +} +