8146156: Inconsistent default locale in string formatter methods
Reviewed-by: sherman
--- a/jdk/src/java.base/share/classes/java/io/PrintStream.java Mon Jun 06 09:13:35 2016 +0200
+++ b/jdk/src/java.base/share/classes/java/io/PrintStream.java Mon Jun 06 10:52:21 2016 -0700
@@ -930,8 +930,10 @@
* format string and arguments.
*
* <p> The locale always used is the one returned by {@link
- * java.util.Locale#getDefault() Locale.getDefault()}, regardless of any
- * previous invocations of other formatting methods on this object.
+ * java.util.Locale#getDefault(Locale.Category)} with
+ * {@link java.util.Locale.Category#FORMAT FORMAT} category specified,
+ * regardless of any previous invocations of other formatting methods on
+ * this object.
*
* @param format
* A format string as described in <a
@@ -969,9 +971,11 @@
synchronized (this) {
ensureOpen();
if ((formatter == null)
- || (formatter.locale() != Locale.getDefault()))
+ || (formatter.locale() !=
+ Locale.getDefault(Locale.Category.FORMAT)))
formatter = new Formatter((Appendable) this);
- formatter.format(Locale.getDefault(), format, args);
+ formatter.format(Locale.getDefault(Locale.Category.FORMAT),
+ format, args);
}
} catch (InterruptedIOException x) {
Thread.currentThread().interrupt();
--- a/jdk/src/java.base/share/classes/java/lang/String.java Mon Jun 06 09:13:35 2016 +0200
+++ b/jdk/src/java.base/share/classes/java/lang/String.java Mon Jun 06 10:52:21 2016 -0700
@@ -2718,7 +2718,9 @@
* arguments.
*
* <p> The locale always used is the one returned by {@link
- * java.util.Locale#getDefault() Locale.getDefault()}.
+ * java.util.Locale#getDefault(java.util.Locale.Category)
+ * Locale.getDefault(Locale.Category)} with
+ * {@link java.util.Locale.Category#FORMAT FORMAT} category specified.
*
* @param format
* A <a href="../util/Formatter.html#syntax">format string</a>
--- a/jdk/src/java.base/share/classes/java/util/Formatter.java Mon Jun 06 09:13:35 2016 +0200
+++ b/jdk/src/java.base/share/classes/java/util/Formatter.java Mon Jun 06 10:52:21 2016 -0700
@@ -285,10 +285,10 @@
* lower-case conversion characters except that the result is converted to
* upper case according to the rules of the prevailing {@link java.util.Locale
* Locale}. The result is equivalent to the following invocation of {@link
- * String#toUpperCase()}
+ * String#toUpperCase(Locale)}
*
* <pre>
- * out.toUpperCase() </pre>
+ * out.toUpperCase(Locale.getDefault(Locale.Category.FORMAT)) </pre>
*
* <table cellpadding=5 summary="genConv">
*
@@ -696,10 +696,10 @@
* corresponding lower-case conversion characters except that the result is
* converted to upper case according to the rules of the prevailing {@link
* java.util.Locale Locale}. The result is equivalent to the following
- * invocation of {@link String#toUpperCase()}
+ * invocation of {@link String#toUpperCase(Locale)}
*
* <pre>
- * out.toUpperCase() </pre>
+ * out.toUpperCase(Locale.getDefault(Locale.Category.FORMAT)) </pre>
*
* <h4><a name="dgen">General</a></h4>
*
@@ -2906,7 +2906,7 @@
if (precision != -1 && precision < s.length())
s = s.substring(0, precision);
if (f.contains(Flags.UPPERCASE))
- s = s.toUpperCase();
+ s = s.toUpperCase(Locale.getDefault(Locale.Category.FORMAT));
appendJustified(a, s);
}
@@ -3130,7 +3130,7 @@
trailingZeros(sb, width - len);
}
if (f.contains(Flags.UPPERCASE))
- s = s.toUpperCase();
+ s = s.toUpperCase(Locale.getDefault(Locale.Category.FORMAT));
sb.append(s);
}
@@ -3205,7 +3205,7 @@
trailingZeros(sb, width - len);
}
if (f.contains(Flags.UPPERCASE))
- s = s.toUpperCase();
+ s = s.toUpperCase(Locale.getDefault(Locale.Category.FORMAT));
sb.append(s);
}
@@ -3383,7 +3383,7 @@
if (upper) {
String tmp = s.substring(0, idx);
// don't localize hex
- tmp = tmp.toUpperCase(Locale.US);
+ tmp = tmp.toUpperCase(Locale.ROOT);
va.append(tmp);
} else {
va.append(s, 0, idx);
@@ -3804,7 +3804,7 @@
// justify based on width
if (f.contains(Flags.UPPERCASE)) {
- appendJustified(a, sb.toString().toUpperCase());
+ appendJustified(a, sb.toString().toUpperCase(Locale.getDefault(Locale.Category.FORMAT)));
} else {
appendJustified(a, sb);
}
@@ -3861,7 +3861,8 @@
ampm = dfs.getAmPmStrings();
}
String s = ampm[t.get(Calendar.AM_PM)];
- sb.append(s.toLowerCase(Objects.requireNonNullElse(l, Locale.US)));
+ sb.append(s.toLowerCase(Objects.requireNonNullElse(l,
+ Locale.getDefault(Locale.Category.FORMAT))));
break;
}
case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?)
@@ -3894,7 +3895,8 @@
TimeZone tz = t.getTimeZone();
sb.append(tz.getDisplayName((t.get(Calendar.DST_OFFSET) != 0),
TimeZone.SHORT,
- Objects.requireNonNullElse(l, Locale.US)));
+ Objects.requireNonNullElse(l,
+ Locale.getDefault(Locale.Category.FORMAT))));
break;
}
@@ -3902,7 +3904,8 @@
case DateTime.NAME_OF_DAY_ABBREV: // 'a'
case DateTime.NAME_OF_DAY: { // 'A'
int i = t.get(Calendar.DAY_OF_WEEK);
- Locale lt = Objects.requireNonNullElse(l, Locale.US);
+ Locale lt = Objects.requireNonNullElse(l,
+ Locale.getDefault(Locale.Category.FORMAT));
DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
if (c == DateTime.NAME_OF_DAY)
sb.append(dfs.getWeekdays()[i]);
@@ -3914,7 +3917,8 @@
case DateTime.NAME_OF_MONTH_ABBREV_X: // 'h' -- same b
case DateTime.NAME_OF_MONTH: { // 'B'
int i = t.get(Calendar.MONTH);
- Locale lt = Objects.requireNonNullElse(l, Locale.US);
+ Locale lt = Objects.requireNonNullElse(l,
+ Locale.getDefault(Locale.Category.FORMAT));
DateFormatSymbols dfs = DateFormatSymbols.getInstance(lt);
if (c == DateTime.NAME_OF_MONTH)
sb.append(dfs.getMonths()[i]);
@@ -3985,7 +3989,8 @@
StringBuilder tsb = new StringBuilder();
print(tsb, t, DateTime.AM_PM, l);
- sb.append(tsb.toString().toUpperCase(Objects.requireNonNullElse(l, Locale.US)));
+ sb.append(tsb.toString().toUpperCase(Objects.requireNonNullElse(l,
+ Locale.getDefault(Locale.Category.FORMAT))));
break;
}
case DateTime.DATE_TIME: { // 'c' (Sat Nov 04 12:02:33 EST 1999)
@@ -4023,7 +4028,7 @@
print(sb, t, c, l);
// justify based on width
if (f.contains(Flags.UPPERCASE)) {
- appendJustified(a, sb.toString().toUpperCase());
+ appendJustified(a, sb.toString().toUpperCase(Locale.getDefault(Locale.Category.FORMAT)));
} else {
appendJustified(a, sb);
}
@@ -4093,7 +4098,8 @@
ampm = dfs.getAmPmStrings();
}
String s = ampm[t.get(ChronoField.AMPM_OF_DAY)];
- sb.append(s.toLowerCase(Objects.requireNonNullElse(l, Locale.US)));
+ sb.append(s.toLowerCase(Objects.requireNonNullElse(l,
+ Locale.getDefault(Locale.Category.FORMAT))));
break;
}
case DateTime.SECONDS_SINCE_EPOCH: { // 's' (0 - 99...?)
@@ -4224,7 +4230,8 @@
// this may be in wrong place for some locales
StringBuilder tsb = new StringBuilder();
print(tsb, t, DateTime.AM_PM, l);
- sb.append(tsb.toString().toUpperCase(Objects.requireNonNullElse(l, Locale.US)));
+ sb.append(tsb.toString().toUpperCase(Objects.requireNonNullElse(l,
+ Locale.getDefault(Locale.Category.FORMAT))));
break;
}
case DateTime.DATE_TIME: { // 'c' (Sat Nov 04 12:02:33 EST 1999)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/io/PrintStream/FormatLocale.java Mon Jun 06 10:52:21 2016 -0700
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016, 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 8146156
+ * @summary test whether conversion follows Locale.Category.FORMAT locale.
+ * @run main/othervm FormatLocale
+ */
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.List;
+import java.util.Locale;
+import java.util.Locale.Category;
+import java.util.stream.IntStream;
+
+public class FormatLocale {
+
+ static final float src = 3.14f;
+ static final List<Locale> formatLocale = List.of(Locale.US, Locale.FRANCE);
+ static final List<String> expected = List.of("3.14", "3,14");
+
+ public static void main(String [] args) {
+ IntStream.range(0, formatLocale.size()).forEach(i -> {
+ Locale.setDefault(Locale.Category.FORMAT, formatLocale.get(i));
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ new PrintStream(baos).format("%.2f", src);
+ if (!baos.toString().equals(expected.get(i))) {
+ throw new RuntimeException(
+ "Wrong conversion with PrintStream.format() in locale "
+ + formatLocale.get(i) +
+ ". Expected: " + expected.get(i) +
+ " Returned: " + baos.toString());
+ }
+ });
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Formatter/FormatLocale.java Mon Jun 06 10:52:21 2016 -0700
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2016, 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 8146156
+ * @summary test whether uppercasing follows Locale.Category.FORMAT locale.
+ * @run main/othervm FormatLocale
+ */
+
+import java.time.LocalDate;
+import java.time.Month;
+import java.util.Formatter;
+import java.util.List;
+import java.util.Locale;
+import java.util.Locale.Category;
+import java.util.stream.IntStream;
+
+public class FormatLocale {
+
+ static final Locale TURKISH = new Locale("tr");
+
+ static final List<String> conversions = List.of(
+ "%S",
+ "%S",
+ "%TB",
+ "%G");
+ static final List<Object> src = List.of(
+ "Turkish",
+ "Turkish",
+ LocalDate.of(2016, Month.APRIL, 1),
+ Float.valueOf(100_000_000));
+ static final List<Locale> formatLocale = List.of(
+ Locale.ENGLISH,
+ TURKISH,
+ TURKISH,
+ Locale.FRANCE);
+ static final List<String> expected = List.of(
+ "TURKISH",
+ "TURK\u0130SH",
+ "N\u0130SAN",
+ "1,00000E+08");
+
+ public static void main(String [] args) {
+ StringBuilder sb = new StringBuilder();
+
+ IntStream.range(0, src.size()).forEach(i -> {
+ sb.setLength(0);
+ Locale.setDefault(Locale.Category.FORMAT, formatLocale.get(i));
+ new Formatter(sb).format(conversions.get(i), src.get(i));
+ if (!sb.toString().equals(expected.get(i))) {
+ throw new RuntimeException(
+ "Wrong uppercasing with Formatter.format(" +
+ "\"" + conversions.get(i) + "\"" +
+ ") in locale "
+ + formatLocale.get(i) +
+ ". Expected: " + expected.get(i) +
+ " Returned: " + sb.toString());
+ }
+ });
+ }
+}