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