SLING-8559 - JcrValueMap should allow getting ZonedDateTime values
diff --git a/src/main/java/org/apache/sling/jcr/resource/internal/helper/BooleanConverter.java b/src/main/java/org/apache/sling/jcr/resource/internal/helper/BooleanConverter.java
index 38c2490..7c9e20e 100644
--- a/src/main/java/org/apache/sling/jcr/resource/internal/helper/BooleanConverter.java
+++ b/src/main/java/org/apache/sling/jcr/resource/internal/helper/BooleanConverter.java
@@ -19,6 +19,7 @@
package org.apache.sling.jcr.resource.internal.helper;
import java.math.BigDecimal;
+import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
@@ -87,6 +88,11 @@
return this.getNumber().floatValue();
}
+ @Override
+ public ZonedDateTime toZonedDateTime() {
+ return new CalendarConverter(toCalendar()).toZonedDateTime();
+ }
+
/**
* @see org.apache.sling.jcr.resource.internal.helper.Converter#toCalendar()
*/
diff --git a/src/main/java/org/apache/sling/jcr/resource/internal/helper/CalendarConverter.java b/src/main/java/org/apache/sling/jcr/resource/internal/helper/CalendarConverter.java
index 8385161..cf24f18 100644
--- a/src/main/java/org/apache/sling/jcr/resource/internal/helper/CalendarConverter.java
+++ b/src/main/java/org/apache/sling/jcr/resource/internal/helper/CalendarConverter.java
@@ -18,6 +18,7 @@
*/
package org.apache.sling.jcr.resource.internal.helper;
+import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
@@ -35,6 +36,11 @@
this.value = val;
}
+ @Override
+ public ZonedDateTime toZonedDateTime() {
+ return ZonedDateTime.ofInstant(this.value.toInstant(), this.value.getTimeZone().toZoneId().normalized());
+ }
+
/**
* @see org.apache.sling.jcr.resource.internal.helper.Converter#toCalendar()
*/
diff --git a/src/main/java/org/apache/sling/jcr/resource/internal/helper/Converter.java b/src/main/java/org/apache/sling/jcr/resource/internal/helper/Converter.java
index 42ca217..50acb7c 100644
--- a/src/main/java/org/apache/sling/jcr/resource/internal/helper/Converter.java
+++ b/src/main/java/org/apache/sling/jcr/resource/internal/helper/Converter.java
@@ -20,6 +20,7 @@
import java.math.BigDecimal;
+import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
@@ -72,6 +73,13 @@
Float toFloat();
/**
+ * Convert to ZonedDateTime.
+ * @return Calendar representation of the converted value
+ * @throws IllegalArgumentException if the value cannot be parsed into a calendar
+ */
+ ZonedDateTime toZonedDateTime();
+
+ /**
* Convert to Calendar.
* @return Calendar representation of the converted value
* @throws IllegalArgumentException if the value cannot be parsed into a calendar
diff --git a/src/main/java/org/apache/sling/jcr/resource/internal/helper/DateConverter.java b/src/main/java/org/apache/sling/jcr/resource/internal/helper/DateConverter.java
index 8b81124..9fdb0ff 100644
--- a/src/main/java/org/apache/sling/jcr/resource/internal/helper/DateConverter.java
+++ b/src/main/java/org/apache/sling/jcr/resource/internal/helper/DateConverter.java
@@ -18,6 +18,7 @@
*/
package org.apache.sling.jcr.resource.internal.helper;
+import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
@@ -35,6 +36,11 @@
this.value = val;
}
+ @Override
+ public ZonedDateTime toZonedDateTime() {
+ return new CalendarConverter(toCalendar()).toZonedDateTime();
+ }
+
/**
* @see org.apache.sling.jcr.resource.internal.helper.Converter#toCalendar()
*/
diff --git a/src/main/java/org/apache/sling/jcr/resource/internal/helper/JcrPropertyMapCacheEntry.java b/src/main/java/org/apache/sling/jcr/resource/internal/helper/JcrPropertyMapCacheEntry.java
index ed40e47..2fe32eb 100644
--- a/src/main/java/org/apache/sling/jcr/resource/internal/helper/JcrPropertyMapCacheEntry.java
+++ b/src/main/java/org/apache/sling/jcr/resource/internal/helper/JcrPropertyMapCacheEntry.java
@@ -26,6 +26,7 @@
import java.io.Serializable;
import java.lang.reflect.Array;
import java.math.BigDecimal;
+import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
@@ -381,6 +382,10 @@
} else if (Calendar.class == type) {
return (T) getConverter(value).toCalendar();
+ } else if (ZonedDateTime.class == type) {
+ Calendar calendar = getConverter(value).toCalendar();
+ return (T) ZonedDateTime.ofInstant(calendar.toInstant(), calendar.getTimeZone().toZoneId().normalized());
+
} else if (Value.class == type) {
return (T) this.createValue(value, node);
@@ -407,6 +412,8 @@
return new DateConverter((Date)value);
} else if ( value instanceof Calendar ) {
return new CalendarConverter((Calendar)value);
+ } else if ( value instanceof ZonedDateTime ) {
+ return new ZonedDateTimeConverter((ZonedDateTime)value);
}
// default string based
return new StringConverter(value);
diff --git a/src/main/java/org/apache/sling/jcr/resource/internal/helper/JcrResourceUtil.java b/src/main/java/org/apache/sling/jcr/resource/internal/helper/JcrResourceUtil.java
index 849041b..76b7718 100644
--- a/src/main/java/org/apache/sling/jcr/resource/internal/helper/JcrResourceUtil.java
+++ b/src/main/java/org/apache/sling/jcr/resource/internal/helper/JcrResourceUtil.java
@@ -20,6 +20,7 @@
import java.io.InputStream;
import java.math.BigDecimal;
+import java.time.ZonedDateTime;
import java.util.Calendar;
import javax.jcr.Node;
@@ -146,7 +147,9 @@
throws RepositoryException {
Value val;
ValueFactory fac = session.getValueFactory();
- if(value instanceof Calendar) {
+ if(value instanceof ZonedDateTime) {
+ val = fac.createValue(new ZonedDateTimeConverter((ZonedDateTime)value).toCalendar());
+ } else if(value instanceof Calendar) {
val = fac.createValue((Calendar)value);
} else if (value instanceof InputStream) {
val = fac.createValue(fac.createBinary((InputStream)value));
diff --git a/src/main/java/org/apache/sling/jcr/resource/internal/helper/NumberConverter.java b/src/main/java/org/apache/sling/jcr/resource/internal/helper/NumberConverter.java
index 5045d95..dd0fc28 100644
--- a/src/main/java/org/apache/sling/jcr/resource/internal/helper/NumberConverter.java
+++ b/src/main/java/org/apache/sling/jcr/resource/internal/helper/NumberConverter.java
@@ -19,6 +19,7 @@
package org.apache.sling.jcr.resource.internal.helper;
import java.math.BigDecimal;
+import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
@@ -83,6 +84,11 @@
return this.value.floatValue();
}
+ @Override
+ public ZonedDateTime toZonedDateTime() {
+ return new CalendarConverter(toCalendar()).toZonedDateTime();
+ }
+
/**
* @see org.apache.sling.jcr.resource.internal.helper.Converter#toCalendar()
*/
diff --git a/src/main/java/org/apache/sling/jcr/resource/internal/helper/StringConverter.java b/src/main/java/org/apache/sling/jcr/resource/internal/helper/StringConverter.java
index bd5af3d..9b0ef07 100644
--- a/src/main/java/org/apache/sling/jcr/resource/internal/helper/StringConverter.java
+++ b/src/main/java/org/apache/sling/jcr/resource/internal/helper/StringConverter.java
@@ -19,6 +19,7 @@
package org.apache.sling.jcr.resource.internal.helper;
import java.math.BigDecimal;
+import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.Date;
@@ -85,6 +86,11 @@
return Float.parseFloat(this.toString());
}
+ @Override
+ public ZonedDateTime toZonedDateTime() {
+ return new CalendarConverter(toCalendar()).toZonedDateTime();
+ }
+
/**
* @see org.apache.sling.jcr.resource.internal.helper.Converter#toCalendar()
*/
diff --git a/src/main/java/org/apache/sling/jcr/resource/internal/helper/ZonedDateTimeConverter.java b/src/main/java/org/apache/sling/jcr/resource/internal/helper/ZonedDateTimeConverter.java
new file mode 100644
index 0000000..82cba61
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/resource/internal/helper/ZonedDateTimeConverter.java
@@ -0,0 +1,11 @@
+package org.apache.sling.jcr.resource.internal.helper;
+
+import java.time.ZonedDateTime;
+import java.util.GregorianCalendar;
+
+public class ZonedDateTimeConverter extends CalendarConverter {
+
+ public ZonedDateTimeConverter(ZonedDateTime value) {
+ super(GregorianCalendar.from(value));
+ }
+}
diff --git a/src/test/java/org/apache/sling/jcr/resource/internal/JcrModifiableValueMapTest.java b/src/test/java/org/apache/sling/jcr/resource/internal/JcrModifiableValueMapTest.java
index 205bb2b..a590ac1 100644
--- a/src/test/java/org/apache/sling/jcr/resource/internal/JcrModifiableValueMapTest.java
+++ b/src/test/java/org/apache/sling/jcr/resource/internal/JcrModifiableValueMapTest.java
@@ -25,6 +25,8 @@
import java.io.Serializable;
import java.lang.reflect.Array;
import java.math.BigDecimal;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
@@ -33,6 +35,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicReference;
import javax.jcr.Node;
@@ -72,7 +75,7 @@
}
getSession().save();
}
-
+
private void setProperty(final Node node,
final String propertyName,
final Object propertyValue)
@@ -91,7 +94,7 @@
node.setProperty(propertyName, createValue(propertyValue, node.getSession()));
}
}
-
+
Value createValue(final Object value, final Session session)
throws RepositoryException {
Value val;
@@ -399,4 +402,52 @@
}
-}
+ /**
+ * Test conversions involving ZonedDateTime
+ */
+ public void testZonedDateTimeConversions() throws Exception {
+ this.rootNode.getSession().refresh(false);
+
+ String dateAsIso8601 = "2019-07-04T14:05:37.123+02:00";
+ ZonedDateTime zonedDateTime = ZonedDateTime.parse(dateAsIso8601, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
+ Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone(zonedDateTime.getOffset()));
+ calendar.setTimeInMillis(zonedDateTime.toInstant().toEpochMilli());
+
+ // write property
+ final Node testNode = this.rootNode.addNode("dateConversionTest" + System.currentTimeMillis());
+ testNode.setProperty(PROP1, calendar);
+ testNode.getSession().save();
+
+ // write with property map
+ final ModifiableValueMap pvm = new JcrModifiableValueMap(testNode, getHelperData());
+ pvm.put(PROP2, zonedDateTime);
+ pvm.put(PROP3, dateAsIso8601);
+ getSession().save();
+
+ // read with property map
+ final ValueMap vm = new JcrModifiableValueMap(testNode, getHelperData());
+
+ // check types
+ assertTrue(vm.get(PROP1) instanceof Calendar);
+ assertTrue(vm.get(PROP2) instanceof Calendar);
+ assertTrue(vm.get(PROP3) instanceof String);
+
+ // to ZonedDateTime
+ assertEquals(zonedDateTime, vm.get(PROP1, ZonedDateTime.class)); // from Calendar
+ assertEquals(zonedDateTime, vm.get(PROP2, ZonedDateTime.class)); // from ZonedDateTime
+ assertEquals(zonedDateTime, vm.get(PROP3, ZonedDateTime.class)); // from ISO-8601 String
+
+ // from ZonedDateTime
+ assertEqualsCalendar(calendar, vm.get(PROP2, Calendar.class)); // to Calendar
+ assertEquals(calendar.getTime(), vm.get(PROP2, Date.class)); // to Date
+ assertEquals(dateAsIso8601, vm.get(PROP2, String.class)); // to String
+
+
+ // read properties
+ assertEqualsCalendar(calendar, testNode.getProperty(PROP1).getDate());
+ assertEqualsCalendar(calendar, testNode.getProperty(PROP2).getDate());
+ assertEqualsCalendar(calendar, testNode.getProperty(PROP3).getDate());
+
+ }
+
+}
\ No newline at end of file