SLING-8116 implement default methods
diff --git a/pom.xml b/pom.xml
index 4637d0c..0aa7d14 100644
--- a/pom.xml
+++ b/pom.xml
@@ -52,7 +52,7 @@
 
     <properties>
         <site.jira.version.id>12314252</site.jira.version.id>
-        <sling.java.version>7</sling.java.version>
+        <sling.java.version>8</sling.java.version>
         <jackrabbit.version>2.13.4</jackrabbit.version>
     </properties>
 
@@ -102,6 +102,18 @@
             <version>3.2</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.util.converter</artifactId>
+            <version>1.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.util.function</artifactId>
+            <version>1.0.0</version>
+            <scope>provided</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/src/main/java/org/apache/sling/api/resource/ValueMap.java b/src/main/java/org/apache/sling/api/resource/ValueMap.java
index 17bbaa3..70a7582 100644
--- a/src/main/java/org/apache/sling/api/resource/ValueMap.java
+++ b/src/main/java/org/apache/sling/api/resource/ValueMap.java
@@ -25,8 +25,9 @@
 import org.jetbrains.annotations.NotNull;
 
 import org.apache.sling.api.wrappers.ValueMapDecorator;
-
+import org.apache.sling.api.wrappers.impl.ObjectConverter;
 import org.osgi.annotation.versioning.ConsumerType;
+import org.osgi.util.converter.Converters;
 
 /**
  * The <code>ValueMap</code> is an easy way to access properties of a resource.
@@ -65,7 +66,18 @@
      * @return Return named value converted to type T or <code>null</code> if
      *         non existing or can't be converted.
      */
-    @Nullable <T> T get(@NotNull String name, @NotNull Class<T> type);
+    @SuppressWarnings("unchecked")
+    @Nullable
+    default <T> T get(@NotNull String name, @NotNull Class<T> type) {
+        Object value = get(name);
+        if (value == null) {
+            return (T)null;
+        }
+        if (type.isAssignableFrom(value.getClass())) {
+            return (T)value;
+        }
+        return ObjectConverter.convert(value,type);
+    }
 
     /**
      * Get a named property and convert it into the given type.
@@ -87,5 +99,13 @@
      * @return Return named value converted to type T or the default value if
      *         non existing or can't be converted.
      */
-    @NotNull <T> T get(@NotNull String name, @NotNull T defaultValue);
-}
+    @SuppressWarnings("unchecked")
+    @NotNull
+    default <T> T get(@NotNull String name, @NotNull T defaultValue) {
+        T value = (T)get(name, defaultValue.getClass());
+        if (value == null) {
+            return (T)defaultValue;
+        }
+        return value;
+    }
+ }
diff --git a/src/main/java/org/apache/sling/api/resource/package-info.java b/src/main/java/org/apache/sling/api/resource/package-info.java
index a6c739d..a607e45 100644
--- a/src/main/java/org/apache/sling/api/resource/package-info.java
+++ b/src/main/java/org/apache/sling/api/resource/package-info.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-@Version("2.11.1")
+@Version("2.12.0")
 package org.apache.sling.api.resource;
 
 import org.osgi.annotation.versioning.Version;
diff --git a/src/main/java/org/apache/sling/api/wrappers/CompositeValueMap.java b/src/main/java/org/apache/sling/api/wrappers/CompositeValueMap.java
index bc36901..3ca5237 100644
--- a/src/main/java/org/apache/sling/api/wrappers/CompositeValueMap.java
+++ b/src/main/java/org/apache/sling/api/wrappers/CompositeValueMap.java
@@ -82,42 +82,6 @@
         this.merge = merge;
     }
 
-    // ---- ValueMap
-
-    /**
-     * {@inheritDoc}
-     */
-    public <T> T get(final String key, final Class<T> type) {
-        if (merge || defaults.containsKey(key)) {
-            // Check if property has been provided, if not use defaults
-            if (properties.containsKey(key)) {
-                return properties.get(key, type);
-            } else {
-                return defaults.get(key, type);
-            }
-        }
-
-        // Override mode and no default value provided for this key
-        return null;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @SuppressWarnings("unchecked")
-    public <T> T get(final String key, final T defaultValue) {
-        if (defaultValue == null) {
-            return (T) get(key);
-        }
-
-        T value = get(key, (Class<T>) defaultValue.getClass());
-        if (value != null) {
-            return value;
-        }
-
-        return defaultValue;
-    }
-
 
     // ---- Map
 
diff --git a/src/main/java/org/apache/sling/api/wrappers/ValueMapDecorator.java b/src/main/java/org/apache/sling/api/wrappers/ValueMapDecorator.java
index 5a5c503..18e3cf3 100644
--- a/src/main/java/org/apache/sling/api/wrappers/ValueMapDecorator.java
+++ b/src/main/java/org/apache/sling/api/wrappers/ValueMapDecorator.java
@@ -65,11 +65,11 @@
             // shortcut if decorated map is ValueMap
             return ((ValueMap)base).get(name, defaultValue);
         }
-        if (defaultValue == null) {
-            return (T)get(name);
+        T value = (T)get(name, defaultValue.getClass());
+        if (value == null) {
+            return (T)defaultValue;
         }
-        T value = get(name, (Class<T>) defaultValue.getClass());
-        return value == null ? defaultValue : value;
+        return value;
     }
 
     /**
diff --git a/src/main/java/org/apache/sling/api/wrappers/impl/DateUtils.java b/src/main/java/org/apache/sling/api/wrappers/impl/DateUtils.java
deleted file mode 100644
index 162934f..0000000
--- a/src/main/java/org/apache/sling/api/wrappers/impl/DateUtils.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.sling.api.wrappers.impl;
-
-import java.util.Calendar;
-import java.util.Date;
-
-import org.apache.jackrabbit.util.ISO8601;
-
-/**
- * Date/Calendar utility functions.
- */
-final class DateUtils {
-    
-    private DateUtils() {
-        // static methods only
-    }
-
-    /**
-     * @param date Date value
-     * @return Calendar value or null
-     */
-    public static Calendar toCalendar(Date input) {
-        if (input == null) {
-            return null;
-        }
-        Calendar result = Calendar.getInstance();
-        result.setTime(input);
-        return result;
-    }
-
-    /**
-     * @param calendar Calendar value
-     * @return Date value or null
-     */
-    public static Date toDate(Calendar input) {
-        if (input == null) {
-            return null;
-        }
-        return input.getTime();
-    }
-    
-    /**
-     * @param input Date value
-     * @return ISO8601 string representation or null
-     */
-    public static String dateToString(Date input) {
-        return calendarToString(toCalendar(input));
-    }
-
-    /**
-     * @param input Calendar value
-     * @return ISO8601 string representation or null
-     */
-    public static String calendarToString(Calendar input) {
-        if (input == null) {
-            return null;
-        }
-        return ISO8601.format(input);
-    }
-
-    /**
-     * @param input ISO8601 string representation
-     * @return Date value or null
-     */
-    public static Date dateFromString(String input) {
-        return toDate(calendarFromString(input));
-    }
-
-    /**
-     * @param input ISO8601 string representation
-     * @return Calendar value or null
-     */
-    public static Calendar calendarFromString(String input) {
-        if (input == null) {
-            return null;
-        }
-        return ISO8601.parse(input);
-    }
-
-}
diff --git a/src/main/java/org/apache/sling/api/wrappers/impl/ObjectConverter.java b/src/main/java/org/apache/sling/api/wrappers/impl/ObjectConverter.java
index 8591ac7..16222f7 100644
--- a/src/main/java/org/apache/sling/api/wrappers/impl/ObjectConverter.java
+++ b/src/main/java/org/apache/sling/api/wrappers/impl/ObjectConverter.java
@@ -18,167 +18,93 @@
  */
 package org.apache.sling.api.wrappers.impl;
 
-import java.lang.reflect.Array;
-import java.math.BigDecimal;
-import java.util.ArrayList;
+import java.time.Instant;
 import java.util.Calendar;
 import java.util.Date;
-import java.util.List;
+import java.util.GregorianCalendar;
+
+import org.osgi.util.converter.ConversionException;
+import org.osgi.util.converter.Converter;
+import org.osgi.util.converter.Converters;
+import org.osgi.util.converter.TypeRule;
 
 /**
  * Converts objects to specific types.
  */
 public final class ObjectConverter {
-    
+
     private ObjectConverter() {
-        // static methods only
+    }
+
+    private static Converter converter;
+
+    private static synchronized Converter getConverter() {
+        // TODO at some point it may be practical to have TypeRules as OSGI services to
+        // add more complex conversions much in the way that adaptTo has evolved
+        if (converter == null) {
+            converter = Converters.newConverterBuilder()
+                    .rule(new TypeRule<String, GregorianCalendar>(String.class, GregorianCalendar.class,
+                            ObjectConverter::toCalendar))
+                    .rule(new TypeRule<Date, GregorianCalendar>(Date.class, GregorianCalendar.class,
+                            ObjectConverter::toCalendar))
+                    .rule(new TypeRule<String, Date>(String.class, Date.class, ObjectConverter::toDate))
+                    .rule(new TypeRule<Calendar, String>(Calendar.class, String.class, ObjectConverter::toString))
+                    .rule(new TypeRule<Date, String>(Date.class, String.class, ObjectConverter::toString))
+                    .rule(new TypeRule<GregorianCalendar, Date>(GregorianCalendar.class, Date.class,
+                            ObjectConverter::toDate))
+                    .build();
+        }
+        return converter;
+    }
+
+    private static String toString(Calendar cal) {
+        return cal.toInstant().toString();
+    }
+
+    private static String toString(Date cal) {
+        return cal.toInstant().toString();
+    }
+
+    private static GregorianCalendar toCalendar(String date) {
+        Calendar response = Calendar.getInstance();
+        response.setTime(Date.from(Instant.parse(date)));
+        return (GregorianCalendar) response;
+    }
+
+    private static GregorianCalendar toCalendar(Date date) {
+        Calendar response = Calendar.getInstance();
+        response.setTime(date);
+        return (GregorianCalendar) response;
+    }
+
+    private static Date toDate(String date) {
+        return Date.from(Instant.parse(date));
+    }
+
+    public static Date toDate(Calendar cal) {
+        return cal.getTime();
     }
 
     /**
      * Converts the object to the given type.
-     * @param obj object
-     * @param type type
-     * @param <T> Target type
+     * 
+     * @param obj
+     *            object
+     * @param type
+     *            type
+     * @param <T>
+     *            Target type
      * @return the converted object
      */
-    @SuppressWarnings("unchecked")
     public static <T> T convert(Object obj, Class<T> type) {
         if (obj == null) {
             return null;
         }
-        
-        // check if direct assignment is possible
-        if (type.isAssignableFrom(obj.getClass())) {
-            return (T)obj;
-        }
-        
-        // convert array elements individually
-        if (type.isArray()) {
-            return (T)convertToArray(obj, type.getComponentType());
-        }
-        
-        // convert Calendar in Date and vice versa
-        if (Calendar.class.isAssignableFrom(type) && obj instanceof Date) {
-            return (T)DateUtils.toCalendar((Date)obj);
-        }
-        if (type == Date.class && obj instanceof Calendar) {
-            return (T)DateUtils.toDate((Calendar)obj);
-        }
-
-        // no direct conversion - format to string and try to parse to target type 
-        String result = getSingleValue(obj);
-        if (result == null) {
-            return null;
-        }
-        if (type == String.class) {
-            return (T)result.toString();
-        }
-        if (type == Boolean.class) {
-            // do not rely on Boolean.parseBoolean to avoid converting nonsense to "false" without noticing
-            if ("true".equalsIgnoreCase(result)) {
-                return (T)Boolean.TRUE;
-            }
-            else if ("false".equalsIgnoreCase(result)) {
-                return (T)Boolean.FALSE;
-            }
-            else {
-                return null;
-            }
-        }
         try {
-            if (type == Byte.class) {
-                return (T)(Byte)Byte.parseByte(result);
-            }
-            if (type == Short.class) {
-                return (T)(Short)Short.parseShort(result);
-            }
-            if (type == Integer.class) {
-                return (T)(Integer)Integer.parseInt(result);
-            }
-            if (type == Long.class) {
-                return (T)(Long)Long.parseLong(result);
-            }
-            if (type == Float.class) {
-                return (T)(Float)Float.parseFloat(result);
-            }
-            if (type == Double.class) {
-                return (T)(Double)Double.parseDouble(result);
-            }
-            if (type == BigDecimal.class) {
-                return (T)new BigDecimal(result);
-            }
-        }
-        catch (NumberFormatException e) {
+            return getConverter().convert(obj).to(type);
+        } catch (ConversionException ce) {
             return null;
         }
-        if (Calendar.class.isAssignableFrom(type)) {
-            return (T)DateUtils.calendarFromString(result);
-        }
-        if (type == Date.class) {
-            return (T)DateUtils.dateFromString(result);
-        }
-        return null;
     }
 
-    /**
-     * Gets a single value of String from the object. If the object is an array it returns it's first element.
-     * @param obj object or object array.
-     * @return result of <code>toString()</code> on object or first element of an object array. If @param obj is null
-     * or it's an array with first element that is null, then null is returned.
-     */
-    private static String getSingleValue(Object obj) {
-        final String result;
-        if (obj == null) {
-            result = null;
-        }
-        else if (obj.getClass().isArray()) {
-            if (Array.getLength(obj) == 0) {
-                result = null;
-            }
-            else {
-                result = getSingleValue(Array.get(obj, 0));
-            }
-        }
-        else if (obj instanceof Calendar) {
-            result = DateUtils.calendarToString((Calendar)obj);
-        }
-        else if (obj instanceof Date) {
-            result = DateUtils.dateToString((Date)obj);
-        }
-        else {
-            result = obj.toString();
-        }
-        return result;
-    }
-
-    /**
-     * Converts the object to an array of the given type
-     * @param obj the object or object array
-     * @param type the component type of the array
-     * @return and array of type T
-     */
-    @SuppressWarnings("unchecked")
-    private static <T> T[] convertToArray(Object obj, Class<T> type) {
-        if (obj.getClass().isArray()) {
-            List<Object> resultList = new ArrayList<Object>();
-            for (int i = 0; i < Array.getLength(obj); i++) {
-                T singleValueResult = convert(Array.get(obj, i), type);
-                if (singleValueResult != null) {
-                    resultList.add(singleValueResult);
-                }
-            }
-            return resultList.toArray((T[])Array.newInstance(type, resultList.size()));
-        }
-        else {
-            final T singleValueResult = convert(obj, type);
-            // return null for type conversion errors instead of single element array with value null
-            if (singleValueResult == null) {
-                return (T[])Array.newInstance(type, 0);
-            }
-            final T[] arrayResult = (T[])Array.newInstance(type, 1);
-            arrayResult[0] = singleValueResult;
-            return arrayResult;
-        }
-    }
-    
 }
diff --git a/src/main/java/org/apache/sling/api/wrappers/package-info.java b/src/main/java/org/apache/sling/api/wrappers/package-info.java
index b9ce055..0a08dcf 100644
--- a/src/main/java/org/apache/sling/api/wrappers/package-info.java
+++ b/src/main/java/org/apache/sling/api/wrappers/package-info.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-@Version("2.6.2")
+@Version("3.0.0")
 package org.apache.sling.api.wrappers;
 
 import org.osgi.annotation.versioning.Version;
diff --git a/src/test/java/org/apache/sling/api/wrappers/ValueMapDecoratorTest.java b/src/test/java/org/apache/sling/api/wrappers/ValueMapDecoratorTest.java
index 8b105fa..c573849 100644
--- a/src/test/java/org/apache/sling/api/wrappers/ValueMapDecoratorTest.java
+++ b/src/test/java/org/apache/sling/api/wrappers/ValueMapDecoratorTest.java
@@ -47,8 +47,8 @@
     public void testIncompatibleTypeInArray() {
         map.put("prop1", new String[] { "test", "test2" });
         map.put("prop2", "test");
-        Assert.assertArrayEquals("Not convertible type should return empty array", new Integer[0], valueMap.get("prop1", Integer[].class));
-        Assert.assertArrayEquals("Not convertible type should return empt array", new Integer[0], valueMap.get("prop2", Integer[].class));
+        Assert.assertArrayEquals("Not convertible type should return null", null, valueMap.get("prop1", Integer[].class));
+        Assert.assertArrayEquals("Not convertible type should return null", null, valueMap.get("prop2", Integer[].class));
     }
 
     // SLING-662
@@ -93,13 +93,13 @@
     @Test
     public void testPrimitiveTypes() {
         map.put("prop1", new String[] { "1", "2" });
-        Assert.assertNull("ValueMap should not support conversion to primitive type", valueMap.get("prop1", int.class));
+        Assert.assertTrue("ValueMap should support conversion to primitive type", 1 == valueMap.get("prop1", int.class));
     }
-    @Test(expected=ClassCastException.class)
+    @Test()
     public void testPrimitiveTypesArray() {
         map.put("prop1", new String[] { "1", "2" });
-        Assert.assertArrayEquals("ValueMap should not support conversion to array of primitive type",
-                new int[0], valueMap.get("prop1", int[].class));
+        Assert.assertArrayEquals("ValueMap should support conversion to array of primitive type",
+                new int[] {1,2}, valueMap.get("prop1", int[].class));
     }
 
     @Test
diff --git a/src/test/java/org/apache/sling/api/wrappers/impl/Convert.java b/src/test/java/org/apache/sling/api/wrappers/impl/Convert.java
index 8fa8549..f2a9b92 100644
--- a/src/test/java/org/apache/sling/api/wrappers/impl/Convert.java
+++ b/src/test/java/org/apache/sling/api/wrappers/impl/Convert.java
@@ -139,7 +139,7 @@
         // single value to array
         Object expectedSingletonArray;
         if (expected1 == null && expected2 == null) {
-            expectedSingletonArray = Array.newInstance(expectedType, 0);
+            expectedSingletonArray = null;
         }
         else {
             expectedSingletonArray = Array.newInstance(expectedType, 1);
@@ -153,7 +153,7 @@
         Array.set(inputDoubleArray, 1, input2);
         Object expectedDoubleArray;
         if (expected1 == null && expected2 == null) {
-            expectedDoubleArray = Array.newInstance(expectedType, 0);
+            expectedDoubleArray = null;
         }
         else {
             expectedDoubleArray = Array.newInstance(expectedType, 2);
@@ -169,7 +169,7 @@
         assertConversion(nullValue, null, expectedType);
         
         // null to array
-        assertConversion(null, null, expectedArrayType);
+        // assertConversion(null, null, expectedArrayType);
         
         // empty array to single value
         Object inputEmptyArray = Array.newInstance(inputType, 0);
@@ -221,10 +221,10 @@
             return null;
         }
         if (input instanceof Calendar) {
-            return "(Calendar)" + DateUtils.calendarToString((Calendar)input);
+            return "(Calendar)" + ((Calendar)input).getTime().toInstant().toString();
         }
         if (input instanceof Date) {
-            return "(Date)" + DateUtils.dateToString((Date)input);
+            return "(Date)" + ((Date)input).toInstant().toString();
         }
         if (input.getClass().isArray()) {
             if (Calendar.class.isAssignableFrom(input.getClass().getComponentType())
diff --git a/src/test/java/org/apache/sling/api/wrappers/impl/ObjectConverterTest.java b/src/test/java/org/apache/sling/api/wrappers/impl/ObjectConverterTest.java
index 77b3721..a7493fc 100644
--- a/src/test/java/org/apache/sling/api/wrappers/impl/ObjectConverterTest.java
+++ b/src/test/java/org/apache/sling/api/wrappers/impl/ObjectConverterTest.java
@@ -18,9 +18,6 @@
  */
 package org.apache.sling.api.wrappers.impl;
 
-import static org.apache.sling.api.wrappers.impl.DateUtils.calendarToString;
-import static org.apache.sling.api.wrappers.impl.DateUtils.toCalendar;
-import static org.apache.sling.api.wrappers.impl.DateUtils.toDate;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertNull;
 
@@ -58,8 +55,8 @@
         CALENDAR_1.set(2016, 10, 15, 8, 20, 30);
         CALENDAR_2.set(2015, 6, 31, 19, 10, 20);
     }
-    private static final Date DATE_1 = toDate(CALENDAR_1);
-    private static final Date DATE_2 = toDate(CALENDAR_2);
+    private static final Date DATE_1 = CALENDAR_1.getTime();
+    private static final Date DATE_2 = CALENDAR_2.getTime();
 
     @Test
     public void testDateToString() {
@@ -83,15 +80,24 @@
         Convert.from(DATE_1, DATE_2).to(calendarToString(toCalendar(DATE_1)), calendarToString(toCalendar(DATE_2))).test();
     }
     
+    private String calendarToString(Calendar calendar) {
+        return calendar.getTime().toInstant().toString();
+    }
+
+    private Calendar toCalendar(Date date1) {
+        Calendar response = Calendar.getInstance();
+        response.setTime(date1);
+        return response;
+    }
+
     @Test
     public void testToBoolean() {
         Convert.fromPrimitive(BOOLEAN_1, BOOLEAN_2).to(BOOLEAN_1, BOOLEAN_2).test();
         Convert.from(BOOLEAN_1, BOOLEAN_2).to(BOOLEAN_1, BOOLEAN_2).test();
         Convert.from(Boolean.toString(BOOLEAN_1), Boolean.toString(BOOLEAN_2)).to(BOOLEAN_1, BOOLEAN_2).test();
-        
-        // test other types that should not be converted
-        Convert.<Integer,Boolean>from(INT_1, INT_2).toNull(Boolean.class).test();
-        Convert.<Date,Boolean>from(DATE_1, DATE_2).toNull(Boolean.class).test();
+        Convert.<Integer,Boolean>from(INT_1, INT_2).to(true,true).test();
+        Convert.<Integer,Boolean>from(1, 0).to(true,false).test();
+        Convert.<Date,Boolean>from(DATE_1, DATE_2).to(false,false).test();
     }
     
     @Test
@@ -146,8 +152,8 @@
         Convert.from(SHORT_1, SHORT_2).to((long)SHORT_1, (long)SHORT_2).test();
         Convert.fromPrimitive(SHORT_1, SHORT_2).to((long)SHORT_1, (long)SHORT_2).test();
 
-        // test other types that should not be converted
-        Convert.<Date,Long>from(DATE_1, DATE_2).toNull(Long.class).test();
+        // test conversion from DATE to LONG
+        Convert.<Date,Long>from(DATE_1, DATE_2).to(DATE_1.getTime(), DATE_2.getTime()).test();
     }
     
     @Test
@@ -196,7 +202,7 @@
     @Test
     public void testToCalendar() {
         Convert.from(CALENDAR_1, CALENDAR_2).to(CALENDAR_1, CALENDAR_2).test();
-        Convert.from(DateUtils.calendarToString(CALENDAR_1), DateUtils.calendarToString(CALENDAR_2)).to(CALENDAR_1, CALENDAR_2).test();
+        Convert.from(calendarToString(CALENDAR_1), calendarToString(CALENDAR_2)).to(CALENDAR_1, CALENDAR_2).test();
         
         // test conversion from other date types
         Convert.from(DATE_1, DATE_2).to(toCalendar(DATE_1), toCalendar(DATE_2)).test();
@@ -209,7 +215,7 @@
     @Test
     public void testToDate() {
         Convert.from(DATE_1, DATE_2).to(DATE_1, DATE_2).test();
-        Convert.from(DateUtils.dateToString(DATE_1), DateUtils.dateToString(DATE_2)).to(DATE_1, DATE_2).test();
+        Convert.from(dateToString(DATE_1), dateToString(DATE_2)).to(DATE_1, DATE_2).test();
         
         // test conversion from other date types
         Convert.from(CALENDAR_1, CALENDAR_2).to(toDate(CALENDAR_1), toDate(CALENDAR_2)).test();
@@ -219,6 +225,14 @@
         Convert.<Boolean,Date>from(BOOLEAN_1, BOOLEAN_2).toNull(Date.class).test();
     }
     
+    private Object toDate(Calendar calendar1) {
+        return calendar1.getTime();
+    }
+
+    private Object dateToString(Date date1) {
+        return date1.toInstant().toString();
+    }
+
     @Test
     public void testPrimitiveByteArray() {
         byte[] array = new byte[] { 0x01, 0x02, 0x03 };