]> granicus.if.org Git - icu/commitdiff
ICU-10017 Git rid of special code in TimePeriod that copies non-immutable Number...
authorTravis Keep <keep94@gmail.com>
Wed, 3 Apr 2013 22:05:00 +0000 (22:05 +0000)
committerTravis Keep <keep94@gmail.com>
Wed, 3 Apr 2013 22:05:00 +0000 (22:05 +0000)
X-SVN-Rev: 33490

icu4j/main/classes/core/src/com/ibm/icu/text/TimeUnitFormat.java
icu4j/main/classes/core/src/com/ibm/icu/util/TimePeriod.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/TimeUnitTest.java

index b7bd8ff388f29a559dd144f1370e634766b407be..f0c1d26efb1eb60bb107ad1fa429776e1fcb6108 100644 (file)
@@ -79,9 +79,7 @@ public class TimeUnitFormat extends MeasureFormat {
      */
     public static final int NUMERIC = 2;
 
-    // For now we don't consider NUMERIC a full-fledged style. NUMERIC is
-    // congruent to ABBREVIATED_NAME unless formatPeriod() is being called.
-    private static final int TOTAL_STYLES = 2;
+    private static final int TOTAL_STYLES = 3;
 
     private static final long serialVersionUID = -3707773153184971529L;
   
@@ -103,10 +101,6 @@ public class TimeUnitFormat extends MeasureFormat {
     private transient MessageFormat hourMinuteSecond;
     private transient boolean isReady;
     private int style;
-    
-    // When style is set to NUMERIC, this field is set to true and the style
-    // field becomes ABBREVIATED_NAME.
-    private boolean isNumericStyle;
 
     /**
      * Create empty format using full name style, for example, "hours". 
@@ -147,10 +141,6 @@ public class TimeUnitFormat extends MeasureFormat {
      * @stable ICU 4.2
      */
     public TimeUnitFormat(ULocale locale, int style) {
-        if (style == NUMERIC) {
-            style = ABBREVIATED_NAME;
-            isNumericStyle = true;
-        }
         if (style < FULL_NAME || style >= TOTAL_STYLES) {
             throw new IllegalArgumentException("style should be either FULL_NAME or ABBREVIATED_NAME style");
         }
@@ -245,7 +235,9 @@ public class TimeUnitFormat extends MeasureFormat {
         Map<String, Object[]> countToPattern = timeUnitToCountToPatterns.get(amount.getTimeUnit());
         double number = amount.getNumber().doubleValue();
         String count = pluralRules.select(number);
-        MessageFormat pattern = (MessageFormat)(countToPattern.get(count))[style];
+        // A hack since NUMERIC really isn't a full fledged style
+        int effectiveStyle = (style == NUMERIC) ? ABBREVIATED_NAME : style;
+        MessageFormat pattern = (MessageFormat)(countToPattern.get(count))[effectiveStyle];
         return pattern.format(new Object[]{amount.getNumber()}, toAppendTo, pos);
     }
     
@@ -259,7 +251,7 @@ public class TimeUnitFormat extends MeasureFormat {
         if (!isReady) {
             setup();
         }
-        if (isNumericStyle) {
+        if (style == NUMERIC) {
             String result = formatPeriodAsNumeric(timePeriod);
             if (result != null) {
                 return result;
@@ -296,6 +288,10 @@ public class TimeUnitFormat extends MeasureFormat {
             for (Entry<String, Object[]> patternEntry : countToPattern.entrySet()) {
               String count = patternEntry.getKey();
               for (int styl = FULL_NAME; styl < TOTAL_STYLES; ++styl) {
+                  if (styl == NUMERIC) {
+                      // Numeric isn't a real style, so skip it.
+                      continue;
+                  }
                 MessageFormat pattern = (MessageFormat)(patternEntry.getValue())[styl];
                 pos.setErrorIndex(-1);
                 pos.setIndex(oldPos);
index 1ed5ff06ca33a76a0eba6a012eaf38ee6702ddc4..f1af89b1843b92bf5683e035562af7974b43b19c 100644 (file)
@@ -6,15 +6,10 @@
  */
 package com.ibm.icu.util;
 
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.math.BigInteger;
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.NoSuchElementException;
 
-import com.ibm.icu.math.BigDecimal;
-
 /**
  * TimePeriod represents a time period.  TimePeriod objects are immutable.
  * <p>Example usage:
@@ -60,9 +55,8 @@ public final class TimePeriod implements Iterable<TimeUnitAmount> {
      * Returns a new TimePeriod that matches the given time unit amounts.
      * @param amounts the TimeUnitAmounts. Must be non-empty. Normalization of the
      *   amounts and inclusion/exclusion of 0 amounts is up to caller. The Number
-     *   in each TimeUnitAmount must either be a Byte, Short, Integer, Long, Float,
-     *   Double, BigInteger, or BigDecimal or it must implement Cloneable and have
-     *   a public clone method.
+     *   object in each TimeUnitAmount must not change. Otherwise the created
+     *   TimePeriod object may not work as expected.
      * @return the new TimePeriod object
      * @throws IllegalArgumentException if multiple TimeUnitAmount objects match
      * the same time unit or if any but the smallest TimeUnit has a fractional value
@@ -81,7 +75,7 @@ public final class TimePeriod implements Iterable<TimeUnitAmount> {
             // This line is necessary to guarantee immutability of the TimePeriod
             // class. A Number object, which is in TimeUnitAmount, need not be immutable,
             // but Double is immutable.
-            fields[index] = cloneIfNecessary(tua);
+            fields[index] = tua;
             size++;
         }
         if (size == 0) {
@@ -111,7 +105,7 @@ public final class TimePeriod implements Iterable<TimeUnitAmount> {
      * @draft ICU 52
      */
     public TimeUnitAmount getAmount(TimeUnit timeUnit) {
-        return cloneIfNecessary(fields[timeUnit.getIndex()]);
+        return fields[timeUnit.getIndex()];
     }
 
     /**
@@ -166,43 +160,6 @@ public final class TimePeriod implements Iterable<TimeUnitAmount> {
         return result;
     }
     
-    private static TimeUnitAmount cloneIfNecessary(TimeUnitAmount tua) {
-        if (tua == null) {
-            return null;
-        }
-        Number number = tua.getNumber();
-        if (number instanceof Double || number instanceof Integer ||
-            number instanceof Long || number instanceof Float ||
-            number instanceof Byte || number instanceof Short ||
-            number instanceof BigInteger || number instanceof BigDecimal) {
-          return tua;            
-        }
-        return new TimeUnitAmount(cloneNumber(number), tua.getTimeUnit());
-    }
-    
-    private static Number cloneNumber(Number number) {
-        // Since Number doesn't implement Cloneable, we have to use reflection
-        // to find the clone() method. If this method throws an exception, it
-        // means that the subclass of Number can't be cloned.
-        Class<? extends Number> clz = number.getClass();
-        Method cloneMethod;
-        try {
-            cloneMethod = clz.getMethod("clone");
-            cloneMethod.setAccessible(true);
-            return (Number) cloneMethod.invoke(number);
-        } catch (NoSuchMethodException e) {
-            throw new RuntimeException(e);
-        } catch (SecurityException e) {
-            throw new RuntimeException(e);
-        } catch (IllegalAccessException e) {
-            throw new RuntimeException(e);
-        } catch (IllegalArgumentException e) {
-            throw new RuntimeException(e);
-        } catch (InvocationTargetException e) {
-            throw new RuntimeException(e);
-        }
-    }
-    
     private class TPIterator implements Iterator<TimeUnitAmount> {
         
         private int index = 0;
index d9b4d9f1b54fe4cbb332ad46dc7fc28f7ff8b455..eb324dfe4d38497694b4f8443444c47c7cb92e2c 100644 (file)
@@ -88,6 +88,7 @@ public class TimeUnitTest extends TestFmwk {
     }
 
     public void TestAPI() {
+        try {
         TimeUnitFormat format = new TimeUnitFormat();
         format.setLocale(new ULocale("pt_BR"));
         formatParsing(format);
@@ -110,6 +111,9 @@ public class TimeUnitTest extends TestFmwk {
         format = new TimeUnitFormat(new Locale("ja"));
         format.setNumberFormat(NumberFormat.getNumberInstance(new Locale("en")));
         formatParsing(format);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
     }
 
     /*
@@ -398,21 +402,20 @@ public class TimeUnitTest extends TestFmwk {
         }
     }
     
-    public void TestTimePeriodWithMutableNumber() {
-        MutableInt mutableInput = new MutableInt(3);
-        TimePeriod tp = TimePeriod.forAmounts(
-                new TimeUnitAmount(mutableInput, TimeUnit.HOUR));
-        mutableInput.set(5);
-        MutableInt mutableOutput = (MutableInt) tp.getAmount(TimeUnit.HOUR).getNumber();
-        assertEquals(
-                "Mutating input shouldn't affect TimePeriod.",
-                3,
-                mutableOutput.intValue());
-        mutableOutput.set(5);
-        assertEquals(
-                "Mutating output shouldn't affect TimePeriod.",
-                3,
-                ((MutableInt) tp.getAmount(TimeUnit.HOUR).getNumber()).intValue());       
+    public void TestTimePeriodEqualsHashCode() {
+        TimePeriod our_19m_28s = TimePeriod.forAmounts(
+                new TimeUnitAmount(28.0, TimeUnit.SECOND),
+                new TimeUnitAmount(19.0, TimeUnit.MINUTE));
+        assertEquals("TimePeriod equals", _19m_28s, our_19m_28s);
+        assertEquals("Hash code", _19m_28s.hashCode(), our_19m_28s.hashCode());
+        TimePeriod our_19m_29s = TimePeriod.forAmounts(
+                new TimeUnitAmount(29.0, TimeUnit.SECOND),
+                new TimeUnitAmount(19.0, TimeUnit.MINUTE));
+        assertNotEquals("TimePeriod not equals", _19m_28s, our_19m_29s);
+        
+        // It may be possible for non-equal objects to have equal hashCodes, but we
+        // are betting on the probability of that to be miniscule.
+        assertNotEquals("TimePeriod hash not equals", _19m_28s.hashCode(), our_19m_29s.hashCode());
     }
     
     private void verifyFormatPeriod(String desc, TimeUnitFormat tuf, Object[][] testData) {
@@ -429,46 +432,4 @@ public class TimeUnitTest extends TestFmwk {
             errln(builder.toString());
         }
     }
-    
-    private static class MutableInt extends Number implements Cloneable {
-
-        private int value;
-        
-        public MutableInt(int x) {
-            value = x;
-        }
-        
-        @Override
-        public int intValue() {
-            return value;
-        }
-
-        @Override
-        public long longValue() {
-            return value;
-        }
-
-        @Override
-        public float floatValue() {
-            return value;
-        }
-
-        @Override
-        public double doubleValue() {
-            return value;
-        }
-        
-        public void set(int x) {
-            value = x;
-        }
-        
-        @Override
-        public MutableInt clone() {
-            try {
-                return (MutableInt) super.clone();
-            } catch (CloneNotSupportedException e) {
-                return null;
-            }
-        }
-    }
 }