You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by ab...@apache.org on 2019/06/10 13:53:10 UTC

[cayenne] 01/04: CAY-2557 Add java.time.Duration and java.time.Period to supported types

This is an automated email from the ASF dual-hosted git repository.

abulatski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit c2c96f91578ec3d564eb135f10e20d8fe09cba8a
Author: Arseni Bulatski <an...@gmail.com>
AuthorDate: Wed Apr 3 17:05:58 2019 +0300

    CAY-2557 Add java.time.Duration and java.time.Period to supported types
---
 RELEASE-NOTES.txt                                  |  1 +
 .../org/apache/cayenne/crypto/CryptoModule.java    | 23 +++---
 .../transformer/value/DurationConverter.java       | 48 ++++++++++++
 .../crypto/transformer/value/PeriodConverter.java  | 49 ++++++++++++
 .../transformer/value/DurationConverterTest.java   | 46 +++++++++++
 .../transformer/value/PeriodConverterTest.java     | 45 +++++++++++
 .../cayenne/access/types/DurationValueType.java    | 53 +++++++++++++
 .../cayenne/access/types/PeriodValueType.java      | 53 +++++++++++++
 .../cayenne/configuration/server/ServerModule.java |  4 +
 .../apache/cayenne/access/types/Java8TimeIT.java   | 52 +++++++++++--
 .../cayenne/testdo/java8/DurationTestEntity.java   | 28 +++++++
 .../cayenne/testdo/java8/PeriodTestEntity.java     | 28 +++++++
 .../testdo/java8/auto/_DurationTestEntity.java     | 88 ++++++++++++++++++++++
 .../testdo/java8/auto/_PeriodTestEntity.java       | 88 ++++++++++++++++++++++
 .../cayenne/unit/di/server/ServerCaseModule.java   | 10 ++-
 .../src/test/resources/cayenne-java8.xml           |  2 +-
 cayenne-server/src/test/resources/java8.map.xml    | 16 +++-
 .../apache/cayenne/modeler/util/ModelerUtil.java   |  4 +-
 18 files changed, 615 insertions(+), 23 deletions(-)

diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt
index 701329d..188267a 100644
--- a/RELEASE-NOTES.txt
+++ b/RELEASE-NOTES.txt
@@ -27,6 +27,7 @@ CAY-2542 Modeler: redesign ObjRelationship editor dialog
 CAY-2543 Move ResultSetMapping generation from metadata to translator
 CAY-2549 Modeler: Redesign ObjAttribute editor dialog
 CAY-2555 Use explicit ArcId in GraphChangeHandler methods
+CAY-2557 Add java.time.Duration and java.time.Period to supported types
 
 Bug Fixes:
 
diff --git a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModule.java b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModule.java
index 5c75ad5..d7d2039 100644
--- a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModule.java
+++ b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/CryptoModule.java
@@ -18,6 +18,16 @@
  */
 package org.apache.cayenne.crypto;
 
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.Types;
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Period;
+import java.util.Date;
+
 import org.apache.cayenne.access.jdbc.reader.RowReaderFactory;
 import org.apache.cayenne.access.translator.batch.BatchTranslatorFactory;
 import org.apache.cayenne.crypto.batch.CryptoBatchTranslatorFactoryDecorator;
@@ -42,6 +52,7 @@ import org.apache.cayenne.crypto.transformer.value.BytesConverter;
 import org.apache.cayenne.crypto.transformer.value.BytesToBytesConverter;
 import org.apache.cayenne.crypto.transformer.value.DefaultValueTransformerFactory;
 import org.apache.cayenne.crypto.transformer.value.DoubleConverter;
+import org.apache.cayenne.crypto.transformer.value.DurationConverter;
 import org.apache.cayenne.crypto.transformer.value.FloatConverter;
 import org.apache.cayenne.crypto.transformer.value.IntegerConverter;
 import org.apache.cayenne.crypto.transformer.value.LazyValueTransformerFactory;
@@ -49,6 +60,7 @@ import org.apache.cayenne.crypto.transformer.value.LocalDateConverter;
 import org.apache.cayenne.crypto.transformer.value.LocalDateTimeConverter;
 import org.apache.cayenne.crypto.transformer.value.LocalTimeConverter;
 import org.apache.cayenne.crypto.transformer.value.LongConverter;
+import org.apache.cayenne.crypto.transformer.value.PeriodConverter;
 import org.apache.cayenne.crypto.transformer.value.ShortConverter;
 import org.apache.cayenne.crypto.transformer.value.Utf8StringConverter;
 import org.apache.cayenne.crypto.transformer.value.UtilDateConverter;
@@ -57,14 +69,6 @@ import org.apache.cayenne.di.Binder;
 import org.apache.cayenne.di.MapBuilder;
 import org.apache.cayenne.di.Module;
 
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.sql.Types;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.util.Date;
-
 /**
  * Contains cryptography extensions for Cayenne.
  *
@@ -193,6 +197,7 @@ public class CryptoModule implements Module {
         mapBuilder.put(LocalDate.class.getName(), LocalDateConverter.INSTANCE);
         mapBuilder.put(LocalTime.class.getName(), LocalTimeConverter.INSTANCE);
         mapBuilder.put(LocalDateTime.class.getName(), LocalDateTimeConverter.INSTANCE);
-
+        mapBuilder.put(Duration.class.getName(), DurationConverter.INSTANCE);
+        mapBuilder.put(Period.class.getName(), PeriodConverter.INSTANCE);
     }
 }
diff --git a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/value/DurationConverter.java b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/value/DurationConverter.java
new file mode 100644
index 0000000..b2454b3
--- /dev/null
+++ b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/value/DurationConverter.java
@@ -0,0 +1,48 @@
+/*****************************************************************
+ *   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.cayenne.crypto.transformer.value;
+
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
+import java.util.Objects;
+
+/**
+ * @since 4.2
+ */
+public class DurationConverter implements BytesConverter<Duration> {
+
+    public static final BytesConverter<Duration> INSTANCE = new DurationConverter(LongConverter.INSTANCE);
+
+    private BytesConverter<Long> longConverter;
+
+    DurationConverter(BytesConverter<Long> longConverter) {
+        this.longConverter = Objects.requireNonNull(longConverter);
+    }
+
+    @Override
+    public Duration fromBytes(byte[] bytes) {
+        return Duration.of(longConverter.fromBytes(bytes), ChronoUnit.MILLIS);
+    }
+
+    @Override
+    public byte[] toBytes(Duration value) {
+        return longConverter.toBytes(value.toMillis());
+    }
+}
diff --git a/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/value/PeriodConverter.java b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/value/PeriodConverter.java
new file mode 100644
index 0000000..ae2de6d
--- /dev/null
+++ b/cayenne-crypto/src/main/java/org/apache/cayenne/crypto/transformer/value/PeriodConverter.java
@@ -0,0 +1,49 @@
+/*****************************************************************
+ *   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.cayenne.crypto.transformer.value;
+
+import java.nio.charset.Charset;
+import java.time.Period;
+
+/**
+ * @since 4.2
+ */
+public class PeriodConverter implements BytesConverter<Period> {
+
+    private static final String DEFAULT_CHARSET = "UTF-8";
+
+    public static final BytesConverter<Period> INSTANCE = new PeriodConverter();
+
+    private Charset utf8;
+
+    PeriodConverter() {
+        this.utf8 = Charset.forName(DEFAULT_CHARSET);
+    }
+
+    @Override
+    public Period fromBytes(byte[] bytes) {
+        return Period.parse(new String(bytes, utf8));
+    }
+
+    @Override
+    public byte[] toBytes(Period value) {
+        return value.toString().getBytes(utf8);
+    }
+}
diff --git a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/transformer/value/DurationConverterTest.java b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/transformer/value/DurationConverterTest.java
new file mode 100644
index 0000000..18512e8
--- /dev/null
+++ b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/transformer/value/DurationConverterTest.java
@@ -0,0 +1,46 @@
+/*****************************************************************
+ *   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.cayenne.crypto.transformer.value;
+
+import java.time.Duration;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @since 4.2
+ */
+public class DurationConverterTest {
+
+    @Test
+    public void testFromBytes() {
+        assertEquals(Duration.ofDays(10),
+                DurationConverter.INSTANCE.fromBytes(new byte[]{51, 127, -104, 0}));
+
+    }
+
+    @Test
+    public void testToBytes() {
+        assertArrayEquals(new byte[] {51, 127, -104, 0},
+                DurationConverter.INSTANCE.toBytes(Duration.ofDays(10)));
+    }
+}
diff --git a/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/transformer/value/PeriodConverterTest.java b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/transformer/value/PeriodConverterTest.java
new file mode 100644
index 0000000..06371ab
--- /dev/null
+++ b/cayenne-crypto/src/test/java/org/apache/cayenne/crypto/transformer/value/PeriodConverterTest.java
@@ -0,0 +1,45 @@
+/*****************************************************************
+ *   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.cayenne.crypto.transformer.value;
+
+import java.time.Period;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @since 4.2
+ */
+public class PeriodConverterTest {
+
+    @Test
+    public void testFromBytes() {
+        assertEquals(Period.of(10, 5, 20),
+                PeriodConverter.INSTANCE.fromBytes(new byte[]{80, 49, 48, 89, 53, 77, 50, 48, 68}));
+    }
+
+    @Test
+    public void testToBytes() {
+        assertArrayEquals(new byte[]{80, 49, 48, 89, 53, 77, 50, 48, 68},
+                PeriodConverter.INSTANCE.toBytes(Period.of(10, 5, 20)));
+    }
+}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/types/DurationValueType.java b/cayenne-server/src/main/java/org/apache/cayenne/access/types/DurationValueType.java
new file mode 100644
index 0000000..1d2b0f4
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/types/DurationValueType.java
@@ -0,0 +1,53 @@
+/*****************************************************************
+ *   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.cayenne.access.types;
+
+import java.time.Duration;
+
+/**
+ * @since 4.2
+ */
+public class DurationValueType implements ValueObjectType<Duration, String> {
+
+    @Override
+    public Class<String> getTargetType() {
+        return String.class;
+    }
+
+    @Override
+    public Class<Duration> getValueType() {
+        return Duration.class;
+    }
+
+    @Override
+    public Duration toJavaObject(String value) {
+        return Duration.parse(value);
+    }
+
+    @Override
+    public String fromJavaObject(Duration object) {
+        return object.toString();
+    }
+
+    @Override
+    public String toCacheKey(Duration object) {
+        return object.toString();
+    }
+}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/types/PeriodValueType.java b/cayenne-server/src/main/java/org/apache/cayenne/access/types/PeriodValueType.java
new file mode 100644
index 0000000..6455598
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/types/PeriodValueType.java
@@ -0,0 +1,53 @@
+/*****************************************************************
+ *   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.cayenne.access.types;
+
+import java.time.Period;
+
+/**
+ * @since 4.2
+ */
+public class PeriodValueType implements ValueObjectType<Period, String> {
+
+    @Override
+    public Class<String> getTargetType() {
+        return String.class;
+    }
+
+    @Override
+    public Class<Period> getValueType() {
+        return Period.class;
+    }
+
+    @Override
+    public Period toJavaObject(String value) {
+        return Period.parse(value);
+    }
+
+    @Override
+    public String fromJavaObject(Period object) {
+        return object.toString();
+    }
+
+    @Override
+    public String toCacheKey(Period object) {
+        return object.toString();
+    }
+}
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
index 197ad72..92fadaa 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerModule.java
@@ -50,6 +50,7 @@ import org.apache.cayenne.access.types.CharacterValueType;
 import org.apache.cayenne.access.types.DateType;
 import org.apache.cayenne.access.types.DefaultValueObjectTypeRegistry;
 import org.apache.cayenne.access.types.DoubleType;
+import org.apache.cayenne.access.types.DurationValueType;
 import org.apache.cayenne.access.types.ExtendedType;
 import org.apache.cayenne.access.types.ExtendedTypeFactory;
 import org.apache.cayenne.access.types.FloatType;
@@ -58,6 +59,7 @@ import org.apache.cayenne.access.types.LocalDateTimeValueType;
 import org.apache.cayenne.access.types.LocalDateValueType;
 import org.apache.cayenne.access.types.LocalTimeValueType;
 import org.apache.cayenne.access.types.LongType;
+import org.apache.cayenne.access.types.PeriodValueType;
 import org.apache.cayenne.access.types.ShortType;
 import org.apache.cayenne.access.types.TimeType;
 import org.apache.cayenne.access.types.TimestampType;
@@ -423,6 +425,8 @@ public class ServerModule implements Module {
                 .add(LocalDateValueType.class)
                 .add(LocalTimeValueType.class)
                 .add(LocalDateTimeValueType.class)
+                .add(DurationValueType.class)
+                .add(PeriodValueType.class)
                 .add(CharacterValueType.class);
 
         binder.bind(ValueObjectTypeRegistry.class).to(DefaultValueObjectTypeRegistry.class);
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/types/Java8TimeIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/types/Java8TimeIT.java
index df98c8a..632b2be 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/types/Java8TimeIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/types/Java8TimeIT.java
@@ -19,25 +19,29 @@
 
 package org.apache.cayenne.access.types;
 
+import java.sql.SQLException;
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.Period;
+import java.time.temporal.ChronoField;
+
 import org.apache.cayenne.access.DataContext;
 import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.query.ObjectSelect;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.testdo.java8.DurationTestEntity;
 import org.apache.cayenne.testdo.java8.LocalDateTestEntity;
 import org.apache.cayenne.testdo.java8.LocalDateTimeTestEntity;
 import org.apache.cayenne.testdo.java8.LocalTimeTestEntity;
-import org.apache.cayenne.query.ObjectSelect;
-import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.testdo.java8.PeriodTestEntity;
 import org.apache.cayenne.unit.di.server.CayenneProjects;
 import org.apache.cayenne.unit.di.server.ServerCase;
 import org.apache.cayenne.unit.di.server.UseServerRuntime;
 import org.junit.Before;
 import org.junit.Test;
 
-import java.sql.SQLException;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.time.temporal.ChronoField;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
@@ -56,6 +60,8 @@ public class Java8TimeIT extends ServerCase {
 		dbHelper.deleteAll("LOCAL_DATE_TEST");
 		dbHelper.deleteAll("LOCAL_DATETIME_TEST");
 		dbHelper.deleteAll("LOCAL_TIME_TEST");
+		dbHelper.deleteAll("DURATION_TEST");
+		dbHelper.deleteAll("PERIOD_TEST");
 	}
 
 	@Test
@@ -141,4 +147,34 @@ public class Java8TimeIT extends ServerCase {
 		assertEquals(localDateTime, value2);
 	}
 
+	@Test
+	public void testJava8Duration() {
+		DurationTestEntity durationTestEntity = context.newObject(DurationTestEntity.class);
+		Duration duration = Duration.ofDays(10);
+		durationTestEntity.setDurationField(duration);
+
+		context.commitChanges();
+
+		DurationTestEntity testRead = ObjectSelect.query(DurationTestEntity.class).selectOne(context);
+
+		assertNotNull(testRead.getDurationField());
+		assertEquals(Duration.class, testRead.getDurationField().getClass());
+		assertEquals(duration, testRead.getDurationField());
+	}
+
+	@Test
+	public void testJava8Period() {
+		PeriodTestEntity periodTestEntity = context.newObject(PeriodTestEntity.class);
+		Period period = Period.of(100, 10, 5);
+		periodTestEntity.setPeriodField(period);
+
+		context.commitChanges();
+
+		PeriodTestEntity testRead = ObjectSelect.query(PeriodTestEntity.class).selectOne(context);
+
+		assertNotNull(testRead.getPeriodField());
+		assertEquals(Period.class, testRead.getPeriodField().getClass());
+		assertEquals(period, testRead.getPeriodField());
+	}
+
 }
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/java8/DurationTestEntity.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/java8/DurationTestEntity.java
new file mode 100644
index 0000000..a1048b0
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/java8/DurationTestEntity.java
@@ -0,0 +1,28 @@
+/*****************************************************************
+ *   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.cayenne.testdo.java8;
+
+import org.apache.cayenne.testdo.java8.auto._DurationTestEntity;
+
+public class DurationTestEntity extends _DurationTestEntity {
+
+    private static final long serialVersionUID = 1L; 
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/java8/PeriodTestEntity.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/java8/PeriodTestEntity.java
new file mode 100644
index 0000000..54e720e
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/java8/PeriodTestEntity.java
@@ -0,0 +1,28 @@
+/*****************************************************************
+ *   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.cayenne.testdo.java8;
+
+import org.apache.cayenne.testdo.java8.auto._PeriodTestEntity;
+
+public class PeriodTestEntity extends _PeriodTestEntity {
+
+    private static final long serialVersionUID = 1L; 
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/java8/auto/_DurationTestEntity.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/java8/auto/_DurationTestEntity.java
new file mode 100644
index 0000000..d0b1fd0
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/java8/auto/_DurationTestEntity.java
@@ -0,0 +1,88 @@
+package org.apache.cayenne.testdo.java8.auto;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.time.Duration;
+
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.BaseProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+
+/**
+ * Class _DurationTestEntity was generated by Cayenne.
+ * It is probably a good idea to avoid changing this class manually,
+ * since it may be overwritten next time code is regenerated.
+ * If you need to make any customizations, please use subclass.
+ */
+public abstract class _DurationTestEntity extends BaseDataObject {
+
+    private static final long serialVersionUID = 1L; 
+
+    public static final String ID_PK_COLUMN = "ID";
+
+    public static final BaseProperty<Duration> DURATION_FIELD = PropertyFactory.createBase("durationField", Duration.class);
+
+    protected Duration durationField;
+
+
+    public void setDurationField(Duration durationField) {
+        beforePropertyWrite("durationField", this.durationField, durationField);
+        this.durationField = durationField;
+    }
+
+    public Duration getDurationField() {
+        beforePropertyRead("durationField");
+        return this.durationField;
+    }
+
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "durationField":
+                return this.durationField;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "durationField":
+                this.durationField = (Duration)val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.durationField);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.durationField = (Duration)in.readObject();
+    }
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/java8/auto/_PeriodTestEntity.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/java8/auto/_PeriodTestEntity.java
new file mode 100644
index 0000000..e84d17d
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/java8/auto/_PeriodTestEntity.java
@@ -0,0 +1,88 @@
+package org.apache.cayenne.testdo.java8.auto;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.time.Period;
+
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.BaseProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+
+/**
+ * Class _PeriodTestEntity was generated by Cayenne.
+ * It is probably a good idea to avoid changing this class manually,
+ * since it may be overwritten next time code is regenerated.
+ * If you need to make any customizations, please use subclass.
+ */
+public abstract class _PeriodTestEntity extends BaseDataObject {
+
+    private static final long serialVersionUID = 1L; 
+
+    public static final String ID_PK_COLUMN = "ID";
+
+    public static final BaseProperty<Period> PERIOD_FIELD = PropertyFactory.createBase("periodField", Period.class);
+
+    protected Period periodField;
+
+
+    public void setPeriodField(Period periodField) {
+        beforePropertyWrite("periodField", this.periodField, periodField);
+        this.periodField = periodField;
+    }
+
+    public Period getPeriodField() {
+        beforePropertyRead("periodField");
+        return this.periodField;
+    }
+
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "periodField":
+                return this.periodField;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "periodField":
+                this.periodField = (Period)val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.periodField);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.periodField = (Period)in.readObject();
+    }
+
+}
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java
index 7969f55..2080b0b 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseModule.java
@@ -18,6 +18,9 @@
  ****************************************************************/
 package org.apache.cayenne.unit.di.server;
 
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
 import org.apache.cayenne.ObjectContext;
 import org.apache.cayenne.access.DataContext;
 import org.apache.cayenne.access.DataNode;
@@ -35,12 +38,14 @@ import org.apache.cayenne.access.types.CharacterValueType;
 import org.apache.cayenne.access.types.DateType;
 import org.apache.cayenne.access.types.DefaultValueObjectTypeRegistry;
 import org.apache.cayenne.access.types.DoubleType;
+import org.apache.cayenne.access.types.DurationValueType;
 import org.apache.cayenne.access.types.FloatType;
 import org.apache.cayenne.access.types.IntegerType;
 import org.apache.cayenne.access.types.LocalDateTimeValueType;
 import org.apache.cayenne.access.types.LocalDateValueType;
 import org.apache.cayenne.access.types.LocalTimeValueType;
 import org.apache.cayenne.access.types.LongType;
+import org.apache.cayenne.access.types.PeriodValueType;
 import org.apache.cayenne.access.types.ShortType;
 import org.apache.cayenne.access.types.TimeType;
 import org.apache.cayenne.access.types.TimestampType;
@@ -130,9 +135,6 @@ import org.apache.cayenne.unit.di.UnitTestLifecycleManager;
 import org.apache.cayenne.unit.util.SQLTemplateCustomizer;
 import org.xml.sax.XMLReader;
 
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-
 public class ServerCaseModule implements Module {
 
     protected DefaultScope testScope;
@@ -217,6 +219,8 @@ public class ServerCaseModule implements Module {
                 .add(LocalDateValueType.class)
                 .add(LocalTimeValueType.class)
                 .add(LocalDateTimeValueType.class)
+                .add(DurationValueType.class)
+                .add(PeriodValueType.class)
                 .add(CharacterValueType.class);
         binder.bind(ValueObjectTypeRegistry.class).to(DefaultValueObjectTypeRegistry.class);
 
diff --git a/cayenne-server/src/test/resources/cayenne-java8.xml b/cayenne-server/src/test/resources/cayenne-java8.xml
index 8d0c655..8e34fc8 100644
--- a/cayenne-server/src/test/resources/cayenne-java8.xml
+++ b/cayenne-server/src/test/resources/cayenne-java8.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <domain xmlns="http://cayenne.apache.org/schema/10/domain"
 	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	 xsi:schemaLocation="http://cayenne.apache.org/schema/10/domain http://cayenne.apache.org/schema/10/domain.xsd"
+	 xsi:schemaLocation="http://cayenne.apache.org/schema/10/domain https://cayenne.apache.org/schema/10/domain.xsd"
 	 project-version="10">
 	<map name="java8"/>
 </domain>
diff --git a/cayenne-server/src/test/resources/java8.map.xml b/cayenne-server/src/test/resources/java8.map.xml
index fb6d3bc..f96f7ef 100644
--- a/cayenne-server/src/test/resources/java8.map.xml
+++ b/cayenne-server/src/test/resources/java8.map.xml
@@ -1,9 +1,13 @@
 <?xml version="1.0" encoding="utf-8"?>
 <data-map xmlns="http://cayenne.apache.org/schema/10/modelMap"
 	 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	 xsi:schemaLocation="http://cayenne.apache.org/schema/10/modelMap http://cayenne.apache.org/schema/10/modelMap.xsd"
+	 xsi:schemaLocation="http://cayenne.apache.org/schema/10/modelMap https://cayenne.apache.org/schema/10/modelMap.xsd"
 	 project-version="10">
 	<property name="defaultPackage" value="org.apache.cayenne.testdo.java8"/>
+	<db-entity name="DURATION_TEST">
+		<db-attribute name="DurationField" type="VARCHAR" length="100"/>
+		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
+	</db-entity>
 	<db-entity name="LOCAL_DATETIME_TEST">
 		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
 		<db-attribute name="TimestampField" type="TIMESTAMP"/>
@@ -16,6 +20,13 @@
 		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
 		<db-attribute name="TimeField" type="TIME"/>
 	</db-entity>
+	<db-entity name="PERIOD_TEST">
+		<db-attribute name="ID" type="INTEGER" isPrimaryKey="true" isMandatory="true"/>
+		<db-attribute name="PeriodField" type="VARCHAR" length="100"/>
+	</db-entity>
+	<obj-entity name="DurationTest" className="org.apache.cayenne.testdo.java8.DurationTestEntity" dbEntityName="DURATION_TEST">
+		<obj-attribute name="durationField" type="java.time.Duration" db-attribute-path="DurationField"/>
+	</obj-entity>
 	<obj-entity name="LocalDateTest" className="org.apache.cayenne.testdo.java8.LocalDateTestEntity" dbEntityName="LOCAL_DATE_TEST">
 		<obj-attribute name="date" type="java.time.LocalDate" db-attribute-path="DateField"/>
 	</obj-entity>
@@ -25,4 +36,7 @@
 	<obj-entity name="LocalTimeTest" className="org.apache.cayenne.testdo.java8.LocalTimeTestEntity" dbEntityName="LOCAL_TIME_TEST">
 		<obj-attribute name="time" type="java.time.LocalTime" db-attribute-path="TimeField"/>
 	</obj-entity>
+	<obj-entity name="PeriodTest" className="org.apache.cayenne.testdo.java8.PeriodTestEntity" dbEntityName="PERIOD_TEST">
+		<obj-attribute name="periodField" type="java.time.Period" db-attribute-path="PeriodField"/>
+	</obj-entity>
 </data-map>
diff --git a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ModelerUtil.java b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ModelerUtil.java
index a8717b8..f788b7d 100644
--- a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ModelerUtil.java
+++ b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/util/ModelerUtil.java
@@ -130,7 +130,9 @@ public final class ModelerUtil {
                 "java.lang.Byte[]",
                 "java.time.LocalDate",
                 "java.time.LocalTime",
-                "java.time.LocalDateTime"
+                "java.time.LocalDateTime",
+                "java.time.Duration",
+                "java.time.Period"
         };
         Arrays.sort(nonPrimitivesNames);