Author: adrianc
Date: Mon Aug 12 15:52:06 2013
New Revision: 1513175

URL: http://svn.apache.org/r1513175
Log:
Fixed some bugs in the date-time conversions. There were problems in the code 
that tried to match types in the java.util.Date class hierarchy, so sometimes 
the wrong converter would be returned by Converters.getConverter().

This commit is a port of Apache OFBiz revisions 1164906, 1350081, 1482507, 
1497890.

Modified:
    
commons/sandbox/convert/trunk/src/main/java/org/apache/commons/convert/Converters.java
    
commons/sandbox/convert/trunk/src/main/java/org/apache/commons/convert/DateTimeConverters.java
    
commons/sandbox/convert/trunk/src/test/java/org/apache/commons/convert/TestDateTimeConverters.java

Modified: 
commons/sandbox/convert/trunk/src/main/java/org/apache/commons/convert/Converters.java
URL: 
http://svn.apache.org/viewvc/commons/sandbox/convert/trunk/src/main/java/org/apache/commons/convert/Converters.java?rev=1513175&r1=1513174&r2=1513175&view=diff
==============================================================================
--- 
commons/sandbox/convert/trunk/src/main/java/org/apache/commons/convert/Converters.java
 (original)
+++ 
commons/sandbox/convert/trunk/src/main/java/org/apache/commons/convert/Converters.java
 Mon Aug 12 15:52:06 2013
@@ -84,31 +84,43 @@ public class Converters {
      */
     public static <S, T> Converter<S, T> getConverter(Class<S> sourceClass, 
Class<T> targetClass) throws ClassNotFoundException {
         String key = 
sourceClass.getName().concat(DELIMITER).concat(targetClass.getName());
-OUTER:
-        do {
-            Converter<?, ?> result = converterMap.get(key);
-            if (result != null) {
-                return Util.cast(result);
-            }
-            if (noConversions.contains(key)) {
-                throw new ClassNotFoundException("No converter found for " + 
key);
-            }
-            for (Converter<?, ?> value : converterMap.values()) {
-                if (value.canConvert(sourceClass, targetClass)) {
-                    converterMap.putIfAbsent(key, value);
-                    continue OUTER;
-                }
-            }
-            for (ConverterCreator value : creators) {
-                result = createConverter(value, sourceClass, targetClass);
+        OUTER:
+            do {
+                Converter<?, ?> result = converterMap.get(key);
                 if (result != null) {
-                    converterMap.putIfAbsent(key, result);
+                    return Util.cast(result);
+                }
+                if (noConversions.contains(key)) {
+                    throw new ClassNotFoundException("No converter found for " 
+ key);
+                }
+                Class<?> foundSourceClass = null;
+                Converter<?, ?> foundConverter = null;
+                for (Converter<?, ?> value : converterMap.values()) {
+                    if (value.canConvert(sourceClass, targetClass)) {
+                        // this converter can deal with the source/target pair
+                        if (foundSourceClass == null || 
foundSourceClass.isAssignableFrom(value.getSourceClass())) {
+                            // remember the current target source class; if we 
find another converter, check
+                            // to see if it's source class is assignable to 
this one, and if so, it means it's
+                            // a child class, so we'll then take that 
converter.
+                            foundSourceClass = value.getSourceClass();
+                            foundConverter = value;
+                        }
+                    }
+                }
+                if (foundConverter != null) {
+                    converterMap.putIfAbsent(key, foundConverter);
                     continue OUTER;
                 }
-            }
-            noConversions.add(key);
-            throw new ClassNotFoundException("No converter found for " + key);
-        } while (true);
+                for (ConverterCreator value : creators) {
+                    result = createConverter(value, sourceClass, targetClass);
+                    if (result != null) {
+                        converterMap.putIfAbsent(key, result);
+                        continue OUTER;
+                    }
+                }
+                noConversions.add(key);
+                throw new ClassNotFoundException("No converter found for " + 
key);
+            } while (true);
     }
 
     private static <S, SS extends S, T, TT extends T> Converter<SS, TT> 
createConverter(ConverterCreator creater, Class<SS> sourceClass, Class<TT> 
targetClass) {

Modified: 
commons/sandbox/convert/trunk/src/main/java/org/apache/commons/convert/DateTimeConverters.java
URL: 
http://svn.apache.org/viewvc/commons/sandbox/convert/trunk/src/main/java/org/apache/commons/convert/DateTimeConverters.java?rev=1513175&r1=1513174&r2=1513175&view=diff
==============================================================================
--- 
commons/sandbox/convert/trunk/src/main/java/org/apache/commons/convert/DateTimeConverters.java
 (original)
+++ 
commons/sandbox/convert/trunk/src/main/java/org/apache/commons/convert/DateTimeConverters.java
 Mon Aug 12 15:52:06 2013
@@ -114,6 +114,24 @@ public class DateTimeConverters implemen
     }
 
     /**
+     * An object that converts a <code>Calendar</code> to a <code>Date</code>.
+     */
+    public static class CalendarToDate extends AbstractConverter<Calendar, 
Date> {
+        public CalendarToDate() {
+            super(Calendar.class, Date.class);
+        }
+
+        @Override
+        public boolean canConvert(Class<?> sourceClass, Class<?> targetClass) {
+            return Util.instanceOf(sourceClass, this.getSourceClass()) && 
Date.class.equals(targetClass);
+        }
+
+        public Date convert(Calendar obj) throws ConversionException {
+            return obj.getTime();
+        }
+    }
+
+    /**
      * An object that converts a <code>Calendar</code> to a <code>Long</code>.
      */
     public static class CalendarToLong extends AbstractConverter<Calendar, 
Long> {
@@ -162,6 +180,40 @@ public class DateTimeConverters implemen
     }
 
     /**
+     * An object that converts a <code>Calendar</code> to a 
<code>Timestamp</code>.
+     */
+    public static class CalendarToTimestamp extends 
AbstractConverter<Calendar, Timestamp> {
+        public CalendarToTimestamp() {
+            super(Calendar.class, Timestamp.class);
+        }
+
+        @Override
+        public boolean canConvert(Class<?> sourceClass, Class<?> targetClass) {
+            return Util.instanceOf(sourceClass, this.getSourceClass()) && 
Timestamp.class.equals(targetClass);
+        }
+
+        public Timestamp convert(Calendar obj) throws ConversionException {
+            return new Timestamp(obj.getTimeInMillis());
+        }
+    }
+
+
+    /**
+     * An object that converts a <code>Date</code> to a <code>Calendar</code>.
+     */
+    public static class DateToCalendar extends GenericLocalizedConverter<Date, 
Calendar> {
+        public DateToCalendar() {
+            super(Date.class, Calendar.class);
+        }
+
+        public Calendar convert(Date obj, Locale locale, TimeZone timeZone, 
String formatString) throws ConversionException {
+            Calendar cal = Calendar.getInstance(timeZone, locale);
+            cal.setTime(obj);
+            return cal;
+        }
+    }
+
+    /**
      * An object that converts a <code>java.util.Date</code> to a
      * <code>java.sql.Date</code>.
      */
@@ -178,8 +230,33 @@ public class DateTimeConverters implemen
         /**
          * Returns <code>obj</code> converted to a <code>java.sql.Date</code>.
          */
+        @SuppressWarnings("deprecation")
         public java.sql.Date convert(Date obj) throws ConversionException {
-            return new java.sql.Date(obj.getTime());
+            Calendar cal = Calendar.getInstance();
+            cal.setTimeInMillis(obj.getTime());
+            return new java.sql.Date(cal.get(Calendar.YEAR) - 1900, 
cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));
+        }
+    }
+
+    /**
+     * An object that converts a <code>java.util.Date</code> to a
+     * <code>java.sql.Time</code>.
+     */
+    public static class DateToSqlTime extends 
AbstractConverter<java.util.Date, java.sql.Time> {
+        public DateToSqlTime() {
+            super(Date.class, java.sql.Time.class);
+        }
+
+        @Override
+        public boolean canConvert(Class<?> sourceClass, Class<?> targetClass) {
+            return sourceClass == this.getSourceClass() && targetClass == 
this.getTargetClass();
+        }
+
+        @SuppressWarnings("deprecation")
+        public java.sql.Time convert(Date obj) throws ConversionException {
+            Calendar cal = Calendar.getInstance();
+            cal.setTimeInMillis(obj.getTime());
+            return new java.sql.Time(cal.get(Calendar.HOUR_OF_DAY), 
cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND));
         }
     }
 
@@ -192,6 +269,11 @@ public class DateTimeConverters implemen
             super(Date.class, String.class);
         }
 
+        @Override
+        public boolean canConvert(Class<?> sourceClass, Class<?> targetClass) {
+            return Date.class.equals(sourceClass) && 
String.class.equals(targetClass);
+        }
+
         /**
          * Converts <code>obj</code> to a <code>String</code> formatted as
          * {@link DateTimeConverters#CALENDAR_FORMAT}. The returned string is
@@ -253,6 +335,20 @@ public class DateTimeConverters implemen
         }
     }
 
+    public static abstract class GenericLocalizedConverter<S, T> extends 
AbstractLocalizedConverter<S, T> {
+        protected GenericLocalizedConverter(Class<S> sourceClass, Class<T> 
targetClass) {
+            super(sourceClass, targetClass);
+        }
+
+        public T convert(S obj) throws ConversionException {
+            return convert(obj, Locale.getDefault(), TimeZone.getDefault(), 
null);
+        }
+
+        public T convert(S obj, Locale locale, TimeZone timeZone) throws 
ConversionException {
+            return convert(obj, locale, timeZone, null);
+        }
+    }
+
     /**
      * An object that converts a <code>Long</code> to a
      * <code>Calendar</code>.
@@ -293,6 +389,11 @@ public class DateTimeConverters implemen
             super(Long.class, Date.class);
         }
 
+        @Override
+        public boolean canConvert(Class<?> sourceClass, Class<?> targetClass) {
+            return Long.class.equals(sourceClass) && 
Date.class.equals(targetClass);
+        }
+
         /**
          * Returns <code>obj</code> converted to a <code>java.util.Date</code>.
          */
@@ -310,6 +411,11 @@ public class DateTimeConverters implemen
             super(Long.class, java.sql.Date.class);
         }
 
+        @Override
+        public boolean canConvert(Class<?> sourceClass, Class<?> targetClass) {
+            return Long.class.equals(sourceClass) && 
java.sql.Date.class.equals(targetClass);
+        }
+
         /**
          * Returns <code>obj</code> converted to a <code>java.sql.Date</code>.
          */
@@ -327,6 +433,11 @@ public class DateTimeConverters implemen
             super(Long.class, java.sql.Time.class);
         }
 
+        @Override
+        public boolean canConvert(Class<?> sourceClass, Class<?> targetClass) {
+            return Long.class.equals(sourceClass) && 
java.sql.Time.class.equals(targetClass);
+        }
+
         /**
          * Returns <code>obj</code> converted to a <code>java.sql.Time</code>.
          */
@@ -344,6 +455,11 @@ public class DateTimeConverters implemen
             super(Long.class, java.sql.Timestamp.class);
         }
 
+        @Override
+        public boolean canConvert(Class<?> sourceClass, Class<?> targetClass) {
+            return Long.class.equals(sourceClass) && 
java.sql.Timestamp.class.equals(targetClass);
+        }
+
         /**
          * Returns <code>obj</code> converted to a 
<code>java.sql.Timestamp</code>.
          */
@@ -383,6 +499,11 @@ public class DateTimeConverters implemen
             super(java.sql.Date.class, String.class);
         }
 
+        @Override
+        public boolean canConvert(Class<?> sourceClass, Class<?> targetClass) {
+            return java.sql.Date.class.equals(sourceClass) && 
String.class.equals(targetClass);
+        }
+
         public String convert(java.sql.Date obj) throws ConversionException {
             return obj.toString();
         }
@@ -430,6 +551,11 @@ public class DateTimeConverters implemen
             super(java.sql.Time.class, String.class);
         }
 
+        @Override
+        public boolean canConvert(Class<?> sourceClass, Class<?> targetClass) {
+            return java.sql.Time.class.equals(sourceClass) && 
String.class.equals(targetClass);
+        }
+
         public String convert(java.sql.Time obj) throws ConversionException {
             return obj.toString();
         }
@@ -499,6 +625,11 @@ public class DateTimeConverters implemen
             super(String.class, Date.class);
         }
 
+        @Override
+        public boolean canConvert(Class<?> sourceClass, Class<?> targetClass) {
+            return String.class.equals(sourceClass) && 
Date.class.equals(targetClass);
+        }
+
         /**
          * Converts <code>obj</code> to a <code>java.util.Date</code>.
          * The string must be formatted as
@@ -537,6 +668,11 @@ public class DateTimeConverters implemen
             super(String.class, java.sql.Date.class);
         }
 
+        @Override
+        public boolean canConvert(Class<?> sourceClass, Class<?> targetClass) {
+            return String.class.equals(sourceClass) && 
java.sql.Date.class.equals(targetClass);
+        }
+
         public java.sql.Date convert(String obj) throws ConversionException {
             return java.sql.Date.valueOf(obj);
         }
@@ -566,6 +702,11 @@ public class DateTimeConverters implemen
             super(String.class, java.sql.Time.class);
         }
 
+        @Override
+        public boolean canConvert(Class<?> sourceClass, Class<?> targetClass) {
+            return String.class.equals(sourceClass) && 
java.sql.Time.class.equals(targetClass);
+        }
+
         public java.sql.Time convert(String obj) throws ConversionException {
             return java.sql.Time.valueOf(obj);
         }
@@ -595,6 +736,11 @@ public class DateTimeConverters implemen
             super(String.class, java.sql.Timestamp.class);
         }
 
+        @Override
+        public boolean canConvert(Class<?> sourceClass, Class<?> targetClass) {
+            return String.class.equals(sourceClass) && 
java.sql.Timestamp.class.equals(targetClass);
+        }
+
         public Timestamp convert(String obj) throws ConversionException {
             return java.sql.Timestamp.valueOf(obj);
         }
@@ -649,6 +795,44 @@ public class DateTimeConverters implemen
 
     /**
      * An object that converts a <code>java.sql.Timestamp</code> to a
+     * <code>java.sql.Date</code>.
+     */
+    public static class TimestampToSqlDate extends 
AbstractConverter<java.sql.Timestamp, java.sql.Date> {
+        public TimestampToSqlDate() {
+            super(java.sql.Timestamp.class, java.sql.Date.class);
+        }
+
+        @Override
+        public boolean canConvert(Class<?> sourceClass, Class<?> targetClass) {
+            return java.sql.Timestamp.class.equals(sourceClass) && 
java.sql.Date.class.equals(targetClass);
+        }
+
+        public java.sql.Date convert(java.sql.Timestamp obj) throws 
ConversionException {
+            return new java.sql.Date(obj.getTime());
+        }
+    }
+
+    /**
+     * An object that converts a <code>java.sql.Timestamp</code> to a
+     * <code>java.sql.Time</code>.
+     */
+    public static class TimestampToSqlTime extends 
AbstractConverter<java.sql.Timestamp, java.sql.Time> {
+        public TimestampToSqlTime() {
+            super(java.sql.Timestamp.class, java.sql.Time.class);
+        }
+
+        @Override
+        public boolean canConvert(Class<?> sourceClass, Class<?> targetClass) {
+            return java.sql.Timestamp.class.equals(sourceClass) && 
java.sql.Time.class.equals(targetClass);
+        }
+
+        public java.sql.Time convert(java.sql.Timestamp obj) throws 
ConversionException {
+            return new java.sql.Time(obj.getTime());
+        }
+    }
+
+    /**
+     * An object that converts a <code>java.sql.Timestamp</code> to a
      * <code>String</code>.
      */
     public static class TimestampToString extends 
AbstractLocalizedConverter<java.sql.Timestamp, String> {
@@ -656,6 +840,11 @@ public class DateTimeConverters implemen
             super(java.sql.Timestamp.class, String.class);
         }
 
+        @Override
+        public boolean canConvert(Class<?> sourceClass, Class<?> targetClass) {
+            return java.sql.Timestamp.class.equals(sourceClass) && 
String.class.equals(targetClass);
+        }
+
         public String convert(java.sql.Timestamp obj) throws 
ConversionException {
             return obj.toString();
         }

Modified: 
commons/sandbox/convert/trunk/src/test/java/org/apache/commons/convert/TestDateTimeConverters.java
URL: 
http://svn.apache.org/viewvc/commons/sandbox/convert/trunk/src/test/java/org/apache/commons/convert/TestDateTimeConverters.java?rev=1513175&r1=1513174&r2=1513175&view=diff
==============================================================================
--- 
commons/sandbox/convert/trunk/src/test/java/org/apache/commons/convert/TestDateTimeConverters.java
 (original)
+++ 
commons/sandbox/convert/trunk/src/test/java/org/apache/commons/convert/TestDateTimeConverters.java
 Mon Aug 12 15:52:06 2013
@@ -20,7 +20,6 @@ package org.apache.commons.convert;
 
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
-import java.util.Calendar;
 import java.util.Collection;
 import java.util.List;
 import java.util.Locale;
@@ -79,23 +78,28 @@ public class TestDateTimeConverters exte
     public void testDateTimeConverters() throws Exception {
         ConverterLoader loader = new DateTimeConverters();
         loader.loadConverters();
-        long currentTime = System.currentTimeMillis();
+        // Java date-related classes default to Jan 1, 1970 00:00:00 in some 
methods,
+        // so we use it here for simplicity.
+        java.util.Date utilDate = new java.util.Date(70, 0, 1, 0, 0, 0);
+        long currentTime = utilDate.getTime();
         java.util.Calendar cal = java.util.Calendar.getInstance();
         cal.setTimeInMillis(currentTime);
-        java.util.Date utilDate = new java.util.Date(currentTime);
-        java.sql.Date sqlDate = new java.sql.Date(cal.get(Calendar.YEAR), 
cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));
-        java.sql.Time sqlTime = new java.sql.Time(cal.get(Calendar.HOUR), 
cal.get(Calendar.MINUTE), cal.get(Calendar.SECOND));
+        java.sql.Date sqlDate = new java.sql.Date(70, 0, 1);
+        java.sql.Time sqlTime = new java.sql.Time(0, 0, 0);
         java.sql.Timestamp timestamp = new java.sql.Timestamp(currentTime);
         // Source class = java.util.Calendar
         DateFormat df = new 
SimpleDateFormat(DateTimeConverters.CALENDAR_FORMAT);
         df.setCalendar(cal);
+        assertConversion("CalendarToDate", new 
DateTimeConverters.CalendarToDate(), cal, utilDate);
         assertConversion("CalendarToLong", new 
DateTimeConverters.CalendarToLong(), cal, currentTime);
         assertConversion("CalendarToString", new 
DateTimeConverters.CalendarToString(), cal, df.format(cal.getTime()));
+        assertConversion("CalendarToTimestamp", new 
DateTimeConverters.CalendarToTimestamp(), cal, timestamp);
         assertToCollection("CalendarToCollection", cal);
         // Source class = java.util.Date
+        assertConversion("DateToCalendar", new 
DateTimeConverters.DateToCalendar(), utilDate, cal);
         assertConversion("DateToLong", new 
DateTimeConverters.GenericDateToLong<java.util.Date>(java.util.Date.class), 
utilDate, currentTime);
-        assertConversion("DateToSqlDate", new 
DateTimeConverters.DateToSqlDate(), new java.util.Date(sqlDate.getTime()), 
sqlDate);
-        assertConversion("DateToSqlDate", new 
DateTimeConverters.DateToSqlDate(), new java.sql.Timestamp(sqlDate.getTime()), 
sqlDate);
+        assertConversion("DateToSqlDate", new 
DateTimeConverters.DateToSqlDate(), utilDate, sqlDate);
+        assertConversion("DateToSqlTime", new 
DateTimeConverters.DateToSqlTime(), utilDate, sqlTime);
         assertConversion("DateToString", new 
DateTimeConverters.DateToString(), utilDate, df.format(cal.getTime()));
         assertConversion("DateToTimestamp", new 
DateTimeConverters.DateToTimestamp(), utilDate, timestamp);
         assertConversion("DateToTimestamp", new 
DateTimeConverters.DateToTimestamp(), timestamp, timestamp, false);
@@ -112,6 +116,8 @@ public class TestDateTimeConverters exte
         assertConversion("SqlTimeToString", new 
DateTimeConverters.SqlTimeToString(), sqlTime, sqlTime.toString());
         // Source class = java.sql.Timestamp
         assertConversion("TimestampToLong", new 
DateTimeConverters.GenericDateToLong<java.sql.Timestamp>(java.sql.Timestamp.class),
 timestamp, currentTime);
+        assertConversion("TimestampToSqlDate", new 
DateTimeConverters.TimestampToSqlDate(), new 
java.sql.Timestamp(sqlDate.getTime()), sqlDate);
+        assertConversion("TimestampToSqlTime", new 
DateTimeConverters.TimestampToSqlTime(), new 
java.sql.Timestamp(sqlDate.getTime()), sqlTime);
         assertConversion("TimestampToString", new 
DateTimeConverters.TimestampToString(), timestamp, timestamp.toString());
         assertToCollection("TimestampToCollection", timestamp);
         // TimeZone tests


Reply via email to