ICU-9919 DateIntervalFormat instances with custom DateIntervalInfo instances should not use the cache to populate themselves.

X-SVN-Rev: 33178
This commit is contained in:
Travis Keep 2013-02-12 01:00:40 +00:00
parent 5f066fb106
commit ca88f9ccba
2 changed files with 117 additions and 21 deletions

View File

@ -308,7 +308,16 @@ public class DateIntervalFormat extends UFormat {
* relavent (locale) to this formatter.
*/
private String fSkeleton = null;
/*
* Needed for efficient deserialization. If set, it means we can use the
* cache to initialize fIntervalPatterns.
*/
private boolean isDateIntervalInfoDefault;
/**
* Interval patterns for this instance's locale.
*/
private transient Map<String, PatternInfo> fIntervalPatterns = null;
@ -339,18 +348,28 @@ public class DateIntervalFormat extends UFormat {
public DateIntervalFormat(String skeleton, DateIntervalInfo dtItvInfo,
SimpleDateFormat simpleDateFormat)
{
SimpleDateFormat dateFormat = simpleDateFormat;
fDateFormat = dateFormat;
fDateFormat = simpleDateFormat;
// freeze date interval info
dtItvInfo.freeze();
fSkeleton = skeleton;
fInfo = dtItvInfo;
isDateIntervalInfoDefault = false;
fFromCalendar = (Calendar) fDateFormat.getCalendar().clone();
fToCalendar = (Calendar) fDateFormat.getCalendar().clone();
initializePattern();
initializePattern(null);
}
private DateIntervalFormat(String skeleton, ULocale locale,
SimpleDateFormat simpleDateFormat)
{
fDateFormat = simpleDateFormat;
fSkeleton = skeleton;
fInfo = new DateIntervalInfo(locale).freeze();
isDateIntervalInfoDefault = true;
fFromCalendar = (Calendar) fDateFormat.getCalendar().clone();
fToCalendar = (Calendar) fDateFormat.getCalendar().clone();
initializePattern(LOCAL_PATTERN_CACHE);
}
/**
@ -423,9 +442,8 @@ public class DateIntervalFormat extends UFormat {
public static final DateIntervalFormat
getInstance(String skeleton, ULocale locale)
{
DateIntervalInfo dtitvinf = new DateIntervalInfo(locale);
DateTimePatternGenerator generator = DateTimePatternGenerator.getInstance(locale);
return new DateIntervalFormat(skeleton, dtitvinf, new SimpleDateFormat(generator.getBestPattern(skeleton), locale));
return new DateIntervalFormat(skeleton, locale, new SimpleDateFormat(generator.getBestPattern(skeleton), locale));
}
@ -514,7 +532,6 @@ public class DateIntervalFormat extends UFormat {
ULocale locale,
DateIntervalInfo dtitvinf)
{
LOCAL_PATTERN_CACHE.clear();
// clone. If it is frozen, clone returns itself, otherwise, clone
// returns a copy.
dtitvinf = (DateIntervalInfo)dtitvinf.clone();
@ -535,8 +552,6 @@ public class DateIntervalFormat extends UFormat {
other.fInfo = (DateIntervalInfo) fInfo.clone();
other.fFromCalendar = (Calendar) fFromCalendar.clone();
other.fToCalendar = (Calendar) fToCalendar.clone();
other.fSkeleton = fSkeleton;
other.fIntervalPatterns = fIntervalPatterns;
return other;
}
@ -808,10 +823,10 @@ public class DateIntervalFormat extends UFormat {
// clone it. If it is frozen, the clone returns itself.
// Otherwise, clone returns a copy
fInfo = (DateIntervalInfo)newItvPattern.clone();
this.isDateIntervalInfoDefault = false;
fInfo.freeze(); // freeze it
LOCAL_PATTERN_CACHE.clear();
if ( fDateFormat != null ) {
initializePattern();
initializePattern(null);
}
}
@ -835,20 +850,25 @@ public class DateIntervalFormat extends UFormat {
/*
* Initialize interval patterns locale to this formatter.
*/
private void initializePattern() {
private void initializePattern(ICUCache<String, Map<String, PatternInfo>> cache) {
String fullPattern = fDateFormat.toPattern();
ULocale locale = fDateFormat.getLocale();
String key;
if ( fSkeleton != null ) {
key = locale.toString() + "+" + fullPattern + "+" + fSkeleton;
} else {
key = locale.toString() + "+" + fullPattern;
String key = null;
Map<String, PatternInfo> patterns = null;
if (cache != null) {
if ( fSkeleton != null ) {
key = locale.toString() + "+" + fullPattern + "+" + fSkeleton;
} else {
key = locale.toString() + "+" + fullPattern;
}
patterns = cache.get(key);
}
Map<String, PatternInfo> patterns = LOCAL_PATTERN_CACHE.get(key);
if ( patterns == null ) {
if (patterns == null) {
Map<String, PatternInfo> intervalPatterns = initializeIntervalPattern(fullPattern, locale);
patterns = Collections.unmodifiableMap(intervalPatterns);
LOCAL_PATTERN_CACHE.put(key, patterns);
if (cache != null) {
cache.put(key, patterns);
}
}
fIntervalPatterns = patterns;
}
@ -1618,6 +1638,6 @@ public class DateIntervalFormat extends UFormat {
private void readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
initializePattern();
initializePattern(isDateIntervalInfoDefault ? LOCAL_PATTERN_CACHE : null);
}
}

View File

@ -1282,4 +1282,80 @@ public class DateIntervalFormatTest extends com.ibm.icu.dev.test.TestFmwk {
errln("hasCode() should return 1.");
}
}
public void TestTicket9919GetInstance() {
// Creating a DateIntervalFormat with a custom DateIntervalInfo
// object used to corrupt the cache.
DateIntervalFormat dif = DateIntervalFormat.getInstance(
"yMd", ULocale.ENGLISH);
Calendar from = Calendar.getInstance();
Calendar to = Calendar.getInstance();
from.set(2013, 3, 26);
to.set(2013, 3, 28);
// Save. This is the correct answer
String expected =
dif.format(from, to, new StringBuffer(), new FieldPosition(0))
.toString();
// Now create a DateIntervalFormat with same skeleton and
// locale, but with a custom DateIntervalInfo. This used
// to corrupt the cache.
DateIntervalInfo dateIntervalInfo =
new DateIntervalInfo(ULocale.ENGLISH);
dateIntervalInfo.setIntervalPattern(
"yMd", Calendar.DATE, "M/d/y \u2013 d");
DateIntervalFormat.getInstance(
"yMd", ULocale.ENGLISH, dateIntervalInfo);
// Now create a DateIntervalFormat with same skeleton and
// locale, but with default DateIntervalInfo. The cache should
// not be corrupted, and we should get the same answer as before.
dif = DateIntervalFormat.getInstance("yMd", ULocale.ENGLISH);
assertEquals(
"Custom DateIntervalInfo objects should not mess up cache",
expected,
dif.format(from, to, new StringBuffer(), new FieldPosition(0))
.toString());
}
public void TestTicket9919Setter() {
// Creating a DateIntervalFormat with a custom DateIntervalInfo
// object used to corrupt the cache.
DateIntervalFormat dif = DateIntervalFormat.getInstance(
"yMd", ULocale.ENGLISH);
Calendar from = Calendar.getInstance();
Calendar to = Calendar.getInstance();
from.set(2013, 3, 26);
to.set(2013, 3, 28);
// Save. This is the correct answer
String expected =
dif.format(from, to, new StringBuffer(), new FieldPosition(0))
.toString();
// Now create a DateIntervalFormat with same skeleton and
// locale, but with a custom DateIntervalInfo. This used
// to corrupt the cache.
DateIntervalInfo dateIntervalInfo =
new DateIntervalInfo(ULocale.ENGLISH);
dateIntervalInfo.setIntervalPattern(
"yMd", Calendar.DATE, "M/d/y \u2013 d");
DateIntervalFormat bad = DateIntervalFormat.getInstance(
"yMd", ULocale.ENGLISH);
bad.setDateIntervalInfo(dateIntervalInfo);
// Now create a DateIntervalFormat with same skeleton and
// locale, but with default DateIntervalInfo. The cache should
// not be corrupted, and we should get the same answer as before.
dif = DateIntervalFormat.getInstance("yMd", ULocale.ENGLISH);
assertEquals(
"Custom DateIntervalInfo objects should not mess up cache",
expected,
dif.format(from, to, new StringBuffer(), new FieldPosition(0))
.toString());
}
}