diff --git a/jdk/src/java.base/share/classes/java/text/DateFormatSymbols.java b/jdk/src/java.base/share/classes/java/text/DateFormatSymbols.java index 955415af8b6..28c3fc7ba00 100644 --- a/jdk/src/java.base/share/classes/java/text/DateFormatSymbols.java +++ b/jdk/src/java.base/share/classes/java/text/DateFormatSymbols.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -606,7 +606,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { try { DateFormatSymbols other = (DateFormatSymbols)super.clone(); - copyMembers(this, other); + copyMembers(new SymbolsCacheEntry(locale), other); return other; } catch (CloneNotSupportedException e) { throw new InternalError(e); @@ -669,7 +669,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { /** * Cache to hold DateFormatSymbols instances per Locale. */ - private static final ConcurrentMap> cachedInstances + private static final ConcurrentMap> cachedInstances = new ConcurrentHashMap<>(3); private transient int lastZoneIndex; @@ -683,10 +683,10 @@ public class DateFormatSymbols implements Serializable, Cloneable { locale = desiredLocale; // Copy values of a cached instance if any. - SoftReference ref = cachedInstances.get(locale); - DateFormatSymbols dfs; - if (ref != null && (dfs = ref.get()) != null) { - copyMembers(dfs, this); + SoftReference ref = cachedInstances.get(locale); + SymbolsCacheEntry sce; + if (ref != null && (sce = ref.get()) != null) { + copyMembers(sce, this); return; } @@ -717,11 +717,11 @@ public class DateFormatSymbols implements Serializable, Cloneable { weekdays = toOneBasedArray(resource.getStringArray("DayNames")); shortWeekdays = toOneBasedArray(resource.getStringArray("DayAbbreviations")); - // Put a clone in the cache - ref = new SoftReference<>((DateFormatSymbols)this.clone()); - SoftReference x = cachedInstances.putIfAbsent(locale, ref); + sce = new SymbolsCacheEntry(locale); + ref = new SoftReference<>(sce); + SoftReference x = cachedInstances.putIfAbsent(locale, ref); if (x != null) { - DateFormatSymbols y = x.get(); + SymbolsCacheEntry y = x.get(); if (y == null) { // Replace the empty SoftReference with ref. cachedInstances.put(locale, ref); @@ -812,7 +812,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { * @param src the source DateFormatSymbols. * @param dst the target DateFormatSymbols. */ - private void copyMembers(DateFormatSymbols src, DateFormatSymbols dst) + private void copyMembers(SymbolsCacheEntry src, DateFormatSymbols dst) { dst.eras = Arrays.copyOf(src.eras, src.eras.length); dst.months = Arrays.copyOf(src.months, src.months.length); @@ -821,7 +821,7 @@ public class DateFormatSymbols implements Serializable, Cloneable { dst.shortWeekdays = Arrays.copyOf(src.shortWeekdays, src.shortWeekdays.length); dst.ampms = Arrays.copyOf(src.ampms, src.ampms.length); if (src.zoneStrings != null) { - dst.zoneStrings = src.getZoneStringsImpl(true); + dst.zoneStrings = getZoneStringsImpl(true); } else { dst.zoneStrings = null; } @@ -842,4 +842,43 @@ public class DateFormatSymbols implements Serializable, Cloneable { } stream.defaultWriteObject(); } + + private static class SymbolsCacheEntry { + + final String eras[]; + final String months[]; + final String shortMonths[]; + final String weekdays[]; + final String shortWeekdays[]; + final String ampms[]; + final String zoneStrings[][]; + final String localPatternChars; + + SymbolsCacheEntry(Locale locale) { + // Initialize the fields from the ResourceBundle for locale. + LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(DateFormatSymbolsProvider.class, locale); + // Avoid any potential recursions + if (!(adapter instanceof ResourceBundleBasedAdapter)) { + adapter = LocaleProviderAdapter.getResourceBundleBased(); + } + ResourceBundle resource = ((ResourceBundleBasedAdapter) adapter).getLocaleData().getDateFormatData(locale); + if (resource.containsKey("Eras")) { + this.eras = resource.getStringArray("Eras"); + } else if (resource.containsKey("long.Eras")) { + this.eras = resource.getStringArray("long.Eras"); + } else if (resource.containsKey("short.Eras")) { + this.eras = resource.getStringArray("short.Eras"); + } else { + this.eras = null; + } + this.months = resource.getStringArray("MonthNames"); + this.shortMonths = resource.getStringArray("MonthAbbreviations"); + this.weekdays = toOneBasedArray(resource.getStringArray("DayNames")); + this.shortWeekdays = toOneBasedArray(resource.getStringArray("DayAbbreviations")); + this.ampms = resource.getStringArray("AmPmMarkers"); + this.zoneStrings = TimeZoneNameUtility.getZoneStrings(locale); + this.localPatternChars = resource.getString("DateTimePatternChars"); + + } + } } diff --git a/jdk/test/java/text/Format/DateFormat/DFSConstructorCloneTest.java b/jdk/test/java/text/Format/DateFormat/DFSConstructorCloneTest.java new file mode 100644 index 00000000000..8632f0932cc --- /dev/null +++ b/jdk/test/java/text/Format/DateFormat/DFSConstructorCloneTest.java @@ -0,0 +1,70 @@ +/* + * 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 8087104 + * @summary Make sure that clone() method is not called from DateFormatSymbols constructor. + */ +import java.text.DateFormatSymbols; + +public class DFSymbolsCloneTest extends DateFormatSymbols { + + private Foo foo; + + public DFSymbolsCloneTest(Foo fooObj) { + if (fooObj == null) { + this.foo = new Foo(); + } else { + this.foo = fooObj; + } + } + + @Override + public Object clone() { + DFSymbolsCloneTest dfsclone = (DFSymbolsCloneTest) super.clone(); + if (this.foo == null) { + throw new RuntimeException("Clone method should not be called from " + + " Superclass(DateFormatSymbols) Constructor..."); + } else { + dfsclone.foo = (Foo) this.foo.clone(); + } + return dfsclone; + } + + public static void main(String[] args) { + DFSymbolsCloneTest dfsctest = new DFSymbolsCloneTest(new Foo()); + } +} + +class Foo { + + public Foo() { + } + + @Override + protected Object clone() { + return new Foo(); + } + +}