From ed1f16a6b71146aff3dd358e16c392de675460e9 Mon Sep 17 00:00:00 2001 From: Yoshito Umaoka Date: Fri, 5 Jun 2015 18:45:59 +0000 Subject: [PATCH] ICU-11733 Check null for ICU DateFormatSymbols wrapped by DateFormatSymbolsICU. So DateFormatSymbols.clone() no longer cause NPE even an instance is not fully initialized. X-SVN-Rev: 37501 --- .../impl/jdkadapter/DateFormatSymbolsICU.java | 94 ++++++++++++++++++- 1 file changed, 91 insertions(+), 3 deletions(-) diff --git a/icu4j/main/classes/localespi/src/com/ibm/icu/impl/jdkadapter/DateFormatSymbolsICU.java b/icu4j/main/classes/localespi/src/com/ibm/icu/impl/jdkadapter/DateFormatSymbolsICU.java index e4d36bcc7d2..fac4ea2627e 100644 --- a/icu4j/main/classes/localespi/src/com/ibm/icu/impl/jdkadapter/DateFormatSymbolsICU.java +++ b/icu4j/main/classes/localespi/src/com/ibm/icu/impl/jdkadapter/DateFormatSymbolsICU.java @@ -1,6 +1,6 @@ /* ******************************************************************************* - * Copyright (C) 2008, International Business Machines Corporation and * + * Copyright (C) 2008-2015, International Business Machines Corporation and * * others. All Rights Reserved. * ******************************************************************************* */ @@ -18,11 +18,29 @@ public class DateFormatSymbolsICU extends java.text.DateFormatSymbols { private DateFormatSymbols fIcuDfs; + // Implementation Note: + // On OpenJDK/Oracle/IBM Java 8, the super class constructor calls + // this.clone(). At this point, fIcuDfs is not yet initialized. + // The cloned instance is only used for optimizing Java's + // DateFormatSymbols initialization and we'll never have an instance + // of DateFormatSymbolsICU with fIcuDfs = null. However, for safety, + // all method implementation uses the pattern - + // + // if (fIcuDfs == null) { + // return super.methodX(); + // } + // return fIcuDfs.methodX(); + // + // to prevent NPE. For more details, please refer #11733 + private DateFormatSymbolsICU(DateFormatSymbols icuDfs) { fIcuDfs = icuDfs; } public static java.text.DateFormatSymbols wrap(DateFormatSymbols icuDfs) { + if (icuDfs == null) { + icuDfs = new DateFormatSymbols(); + } return new DateFormatSymbolsICU(icuDfs); } @@ -33,99 +51,169 @@ public class DateFormatSymbolsICU extends java.text.DateFormatSymbols { @Override public Object clone() { DateFormatSymbolsICU other = (DateFormatSymbolsICU)super.clone(); - other.fIcuDfs = (DateFormatSymbols)this.fIcuDfs.clone(); + if (fIcuDfs != null) { + // fIcuDfs must not be null except for premature instance. + // A premature instance might be created by Java DateFormatSymbols' + // internal cache. See #11733 for more details. + other.fIcuDfs = (DateFormatSymbols)this.fIcuDfs.clone(); + } return other; } @Override public boolean equals(Object obj) { + if (obj == null) { + return false; + } if (obj instanceof DateFormatSymbolsICU) { - return ((DateFormatSymbolsICU)obj).fIcuDfs.equals(this.fIcuDfs); + if (this.fIcuDfs == null) { + return ((DateFormatSymbolsICU)obj).fIcuDfs == null; + } + return this.fIcuDfs.equals(((DateFormatSymbolsICU)obj).fIcuDfs); } return false; } @Override public String[] getAmPmStrings() { + if (fIcuDfs == null) { + return super.getAmPmStrings(); + } return fIcuDfs.getAmPmStrings(); } @Override public String[] getEras() { + if (fIcuDfs == null) { + return super.getEras(); + } return fIcuDfs.getEras(); } public String getLocalePatternChars() { + if (fIcuDfs == null) { + return super.getLocalPatternChars(); + } return fIcuDfs.getLocalPatternChars(); } @Override public String[] getMonths() { + if (fIcuDfs == null) { + return super.getMonths(); + } return fIcuDfs.getMonths(); } @Override public String[] getShortMonths() { + if (fIcuDfs == null) { + return super.getShortMonths(); + } return fIcuDfs.getShortMonths(); } @Override public String[] getShortWeekdays() { + if (fIcuDfs == null) { + return super.getShortWeekdays(); + } return fIcuDfs.getShortWeekdays(); } @Override public String[] getWeekdays() { + if (fIcuDfs == null) { + return super.getWeekdays(); + } return fIcuDfs.getWeekdays(); } @Override public String[][] getZoneStrings() { + if (fIcuDfs == null) { + return super.getZoneStrings(); + } return fIcuDfs.getZoneStrings(); } @Override public int hashCode() { + if (fIcuDfs == null) { + return super.hashCode(); + } return fIcuDfs.hashCode(); } @Override public void setAmPmStrings(String[] newAmpms) { + if (fIcuDfs == null) { + super.setAmPmStrings(newAmpms); + return; + } fIcuDfs.setAmPmStrings(newAmpms); } @Override public void setEras(String[] newEras) { + if (fIcuDfs == null) { + super.setEras(newEras); + return; + } fIcuDfs.setEras(newEras); } @Override public void setLocalPatternChars(String newLocalPatternChars) { + if (fIcuDfs == null) { + super.setLocalPatternChars(newLocalPatternChars); + return; + } fIcuDfs.setLocalPatternChars(newLocalPatternChars); } @Override public void setMonths(String[] newMonths) { + if (fIcuDfs == null) { + super.setMonths(newMonths); + return; + } fIcuDfs.setMonths(newMonths); } @Override public void setShortMonths(String[] newShortMonths) { + if (fIcuDfs == null) { + super.setShortMonths(newShortMonths); + return; + } fIcuDfs.setShortMonths(newShortMonths); } @Override public void setShortWeekdays(String[] newShortWeekdays) { + if (fIcuDfs == null) { + super.setShortWeekdays(newShortWeekdays); + return; + } fIcuDfs.setShortWeekdays(newShortWeekdays); } @Override public void setWeekdays(String[] newWeekdays) { + if (fIcuDfs == null) { + super.setWeekdays(newWeekdays); + return; + } fIcuDfs.setWeekdays(newWeekdays); } @Override public void setZoneStrings(String[][] newZoneStrings) { + if (fIcuDfs == null) { + super.setZoneStrings(newZoneStrings); + return; + } fIcuDfs.setZoneStrings(newZoneStrings); } }