ICU-11742 Merged the fix for Java 8 DateFormatSymbols locale service provider problem (#11733/r37501).

X-SVN-Rev: 37525
diff --git a/main/classes/localespi/src/com/ibm/icu/impl/jdkadapter/DateFormatSymbolsICU.java b/main/classes/localespi/src/com/ibm/icu/impl/jdkadapter/DateFormatSymbolsICU.java
index e4d36bc..fac4ea2 100644
--- a/main/classes/localespi/src/com/ibm/icu/impl/jdkadapter/DateFormatSymbolsICU.java
+++ b/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 @@
 
     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 @@
     @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);
     }
 }