You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2018/09/26 10:53:06 UTC

[isis] 01/06: ISIS-1976: polishing 'Version' and 'ObjectSpecId'

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

ahuber pushed a commit to branch v2
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 6a51e7cc60bf114fdecab99a2b2111819d4b78dd
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Sep 26 08:47:08 2018 +0200

    ISIS-1976: polishing 'Version' and 'ObjectSpecId'
    
    Task-Url: https://issues.apache.org/jira/browse/ISIS-1976
---
 .../isis/commons/internal/base/_NullSafe.java      |   4 +-
 .../apache/isis/commons/internal/base/_With.java   |  23 ++++-
 .../core/metamodel/adapter/oid/OidMarshaller.java  |   4 +-
 .../isis/core/metamodel/adapter/oid/RootOid.java   |  13 ++-
 .../core/metamodel/adapter/version/Version.java    | 114 ++++++++++++---------
 .../metamodel/MetaModelServiceDefault.java         |   2 +-
 .../isis/core/metamodel/spec/ObjectSpecId.java     |  30 +++---
 .../ObjectSpecificationOnStandaloneList.java       |   2 +-
 .../adapter/oid/VersionTest_valueSemantics.java    |  10 +-
 .../adapter/version/VersionTest_differs.java       |   9 +-
 .../spec/ObjectSpecIdTest_constructor.java         |  10 +-
 .../spec/ObjectSpecIdTest_valueSemantics.java      |   4 +-
 .../core/runtime/system/persistence/Utils.java     |   9 +-
 .../core/runtime/system/persistence/Utils.java     |   6 +-
 .../rendering/domainobjects/JsonValueEncoder.java  |   2 +-
 .../JsonValueEncoderTest_appendValueAndFormat.java |   2 +-
 .../JsonValueEncoderTest_asObject.java             |   2 +-
 17 files changed, 144 insertions(+), 102 deletions(-)

diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/base/_NullSafe.java b/core/commons/src/main/java/org/apache/isis/commons/internal/base/_NullSafe.java
index 8d77315..5b63a99 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/base/_NullSafe.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/base/_NullSafe.java
@@ -197,7 +197,7 @@ public final class _NullSafe {
     public static boolean isEmpty(long[] array){ return array==null || array.length == 0;}
     public static boolean isEmpty(short[] array){ return array==null || array.length == 0;}
     public static <T> boolean isEmpty(T[] array){ return array==null || array.length == 0;}
-
+    
     // -- SIZE/LENGTH CHECKS
 
     public static int size(String x){ return x!=null ? x.length() : 0; }
@@ -230,4 +230,6 @@ public final class _NullSafe {
         return map.getOrDefault(key, defaultValue);
     }
 
+
+
 }
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/base/_With.java b/core/commons/src/main/java/org/apache/isis/commons/internal/base/_With.java
index 726e15b..11774ac 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/base/_With.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/base/_With.java
@@ -214,7 +214,27 @@ public final class _With<T> {
      */
     public static <T> T requires(@Nullable T obj, String paramName) {
         if (obj == null) {
-            throw new NullPointerException(String.format("Parameter '%s' is required to be non-null.", paramName));
+            throw new NullPointerException(String.format("Parameter '%s' is required to be present (not null).", paramName));
+        }
+        return obj;
+    }
+    
+    // -- PARAMETER NON-EMPTY CHECK(S)
+
+    /**
+     * Allows for convenient named parameter non-empty-check.
+     * @param obj target for the non-empty-check
+     * @param paramName to use for the exception message, when the non-empty-check fails 
+     * @return {@code obj}
+     * @throws NullPointerException if {@code obj} is {@code null}
+     * @throws IllegalArgumentException if {@code obj} is 'empty'
+     */
+    public static String requiresNotEmpty(@Nullable String obj, String paramName) {
+        if (obj == null) {
+            throw new NullPointerException(String.format("Parameter '%s' is required to be present (not null).", paramName));
+        }
+        if (obj.length()==0) {
+            throw new IllegalArgumentException(String.format("Parameter '%s' is required to be present and not empty.", paramName));
         }
         return obj;
     }
@@ -287,4 +307,5 @@ public final class _With<T> {
 
 
 
+
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/OidMarshaller.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/OidMarshaller.java
index 3ddba76..e2c710e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/OidMarshaller.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/OidMarshaller.java
@@ -189,12 +189,12 @@ public final class OidMarshaller {
         final String versionSequence = getGroup(matcher, 10);
         final String versionUser = getGroup(matcher, 11);
         final String versionUtcTimestamp = getGroup(matcher, 12);
-        final Version version = Version.create(versionSequence, versionUser, versionUtcTimestamp);
+        final Version version = Version.Factory.parse(versionSequence, versionUser, versionUtcTimestamp);
 
         if(collectionName == null) {
             if(aggregateOidParts.isEmpty()) {
                 ensureCorrectType(oidStr, requestedType, RootOid.class);
-                return (T) new RootOid(ObjectSpecId.of(rootObjectType), rootIdentifier, state, version);
+                return (T) RootOid.of(ObjectSpecId.of(rootObjectType), rootIdentifier, state, version);
             } else {
                 throw new RuntimeException("Aggregated Oids are no longer supported");
             }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOid.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOid.java
index d989e9e..1284176 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOid.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/RootOid.java
@@ -76,8 +76,8 @@ public class RootOid implements Oid, Serializable {
     }
 
     public static RootOid create(final ObjectSpecId objectSpecId, final String identifier, final Long versionSequence, final String versionUser, final Long versionUtcTimestamp) {
-        return new RootOid(objectSpecId, identifier, State.PERSISTENT, Version.create(versionSequence,
-                versionUser, versionUtcTimestamp));
+        return new RootOid(objectSpecId, identifier, State.PERSISTENT, 
+                Version.Factory.ifPresent(versionSequence, versionUser, versionUtcTimestamp));
     }
 
     public RootOid(final ObjectSpecId objectSpecId, final String identifier, final State state) {
@@ -106,10 +106,15 @@ public class RootOid implements Oid, Serializable {
      * If specify version sequence, can optionally specify user and/or utc timestamp that the oid was changed.  This is used for informational purposes only.
      */
     public RootOid(final ObjectSpecId objectSpecId, final String identifier, final State state, final Long versionSequence, final String versionUser, final Long versionUtcTimestamp) {
-        this(objectSpecId, identifier, state, Version.create(versionSequence, versionUser, versionUtcTimestamp));
+        this(objectSpecId, identifier, state, Version.Factory.ifPresent(versionSequence, versionUser, versionUtcTimestamp));
     }
 
-    public RootOid(final ObjectSpecId objectSpecId, final String identifier, final State state, final Version version) {
+    
+    public static RootOid of(final ObjectSpecId objectSpecId, final String identifier, final State state, final Version version) {
+        return new RootOid(objectSpecId, identifier, state, version);
+    }
+    
+    private RootOid(final ObjectSpecId objectSpecId, final String identifier, final State state, final Version version) {
 
         requires(objectSpecId, "objectSpecId");
         requires(identifier, "identifier");
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/version/Version.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/version/Version.java
index af02062..9c2d34c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/version/Version.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/version/Version.java
@@ -19,10 +19,14 @@
 
 package org.apache.isis.core.metamodel.adapter.version;
 
+import static org.apache.isis.commons.internal.base._With.mapIfPresentElse;
+
 import java.io.IOException;
 import java.io.Serializable;
 import java.util.Date;
 
+import javax.annotation.Nullable;
+
 import org.apache.isis.core.commons.encoding.DataInputExtended;
 import org.apache.isis.core.commons.encoding.DataOutputExtended;
 import org.apache.isis.core.commons.encoding.Encodable;
@@ -42,55 +46,38 @@ import org.apache.isis.core.metamodel.adapter.oid.OidMarshaller;
  * indicate that the two Version objects are different.
  *
  * <p>
- * The user's name and a timestamp should alos be kept so that when an message
+ * The user's name and a timestamp should also be kept so that when an message
  * is passed to the user it can be of the form "user has change object at time"
  */
-public class Version implements Serializable, Encodable {
+public final class Version implements Serializable, Encodable {
 
     private static final long serialVersionUID = 1L;
 
     private final static OidMarshaller OID_MARSHALLER = OidMarshaller.INSTANCE;
 
-    // -- factory methods
-
-    public static Version create(final Long sequence) {
-        return create(sequence, null, (Long)null);
-    }
-
-    public static Version create(String sequence, String user, String utcTimestamp) {
-        if(sequence == null) {
-            return null;
-        }
-        return create(Long.parseLong(sequence), user, utcTimestamp != null?Long.parseLong(utcTimestamp):null);
-    }
+    // -- FACTORIES
 
-    public static Version create(final Long sequence, final String user, final Date time) {
-        return create(sequence, user, time !=null? time.getTime(): null);
+    public static Version of(long sequence, @Nullable String user) {
+        return of(sequence, user, Factory.EMPTY_TIMESTAMP);
     }
-
-    public static Version create(Long sequence, String user, Long utcTimestamp) {
-        if(sequence == null) {
-            return null;
-        }
+    
+    public static Version of(long sequence, @Nullable String user, long utcTimestamp) {
         return new Version(sequence, user, utcTimestamp);
     }
 
 
-
     // -- constructor, fields
-    private final Long sequence;
+    private final long sequence;
     private final String user;
-    private final Long utcTimestamp;
+    private final long utcTimestamp;
 
-    private Version(Long sequence, String user, Long utcTimestamp) {
+    private Version(long sequence, @Nullable String user, long utcTimestamp) {
         this.sequence = sequence;
         this.user = user;
         this.utcTimestamp = utcTimestamp;
     }
 
-
-
-    // -- encodable
+    // -- Encodable
 
     public Version(final DataInputExtended input) throws IOException {
         this(input.readLong(), input.readUTF(), input.readLong());
@@ -104,8 +91,6 @@ public class Version implements Serializable, Encodable {
         output.writeLong(utcTimestamp);
     }
 
-
-
     // -- getters
     /**
      * The internal, strictly monotonically increasing, version number.
@@ -123,7 +108,7 @@ public class Version implements Serializable, Encodable {
      * <p>
      * May be null.
      */
-    public String getUser() {
+    public @Nullable String getUser() {
         return user;
     }
 
@@ -131,11 +116,11 @@ public class Version implements Serializable, Encodable {
      * The time of the last change, as UTC milliseconds.
      *
      * <p>
-     * May be null.
+     * May be zero.
      *
      * @see #getTime()
      */
-    public Long getUtcTimestamp() {
+    public long getUtcTimestamp() {
         return utcTimestamp;
     }
 
@@ -147,28 +132,21 @@ public class Version implements Serializable, Encodable {
      *
      * @see #getUtcTimestamp()
      */
-    public Date getTime() {
-        return utcTimestamp != null? new Date(this.utcTimestamp): null;
+    public @Nullable Date getTime() {
+        return utcTimestamp!=Factory.EMPTY_TIMESTAMP ? new Date(this.utcTimestamp) : null;
     }
 
-
-
     // -- enString
 
     public String enString() {
         return OID_MARSHALLER.marshal(this);
     }
 
-
-
     // -- equals, hashCode
 
     @Override
     public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + ((sequence == null) ? 0 : sequence.hashCode());
-        return result;
+        return Long.hashCode(sequence);
     }
 
     @Override
@@ -180,12 +158,7 @@ public class Version implements Serializable, Encodable {
         if (getClass() != obj.getClass())
             return false;
         Version other = (Version) obj;
-        if (sequence == null) {
-            if (other.sequence != null)
-                return false;
-        } else if (!sequence.equals(other.sequence))
-            return false;
-        return true;
+        return sequence == other.sequence;
     }
 
     /**
@@ -200,8 +173,6 @@ public class Version implements Serializable, Encodable {
         return !equals(version);
     }
 
-
-
     // -- sequence
 
     @Override
@@ -216,6 +187,47 @@ public class Version implements Serializable, Encodable {
         return Long.toString(sequence, 16);
     }
 
+    // -- SPECIAL CASES
+    
+    /** for convenience*/
+    public static final class Factory {
+        
+        private final static Version EMPTY_VERSION = null;
+        private final static long EMPTY_TIMESTAMP = 0L;
+    
+        public static @Nullable Version ifPresent(@Nullable Long sequence, String user, @Nullable Long utcTimestamp) {
+            return mapIfPresentElse(sequence, __->
+                of(sequence.longValue(), user, timestampOfNullable(utcTimestamp)), EMPTY_VERSION);
+        }
+        
+        public static @Nullable Version ifPresent(@Nullable Long sequence, String user, long utcTimestamp) {
+            return mapIfPresentElse(sequence, __->
+                of(sequence.longValue(), user, utcTimestamp), EMPTY_VERSION);
+        }
+        
+        public static @Nullable Version ifPresent(@Nullable Long sequence, String user) {
+            return mapIfPresentElse(sequence, __->
+                of(sequence.longValue(), user, EMPTY_TIMESTAMP), EMPTY_VERSION);
+        }
+        
+        public static @Nullable Version parse(@Nullable String sequence, String user, @Nullable String utcTimestamp) {
+            return mapIfPresentElse(sequence, __->
+                of(Long.parseLong(sequence), user, parseTimeStamp(utcTimestamp)), EMPTY_VERSION); 
+        }
+        
+        // -- HELPER
+        
+        private static long parseTimeStamp(@Nullable String utcTimestamp) {
+            return utcTimestamp != null ? Long.parseLong(utcTimestamp) : EMPTY_TIMESTAMP;
+        }
+        
+        private static long timestampOfNullable(@Nullable Long utcTimestamp) {
+            return utcTimestamp != null ? utcTimestamp.longValue() : EMPTY_TIMESTAMP;
+        }
+        
+    }
+
+
 
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java
index f5239f7..7025a0b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/services/metamodel/MetaModelServiceDefault.java
@@ -70,7 +70,7 @@ public class MetaModelServiceDefault implements MetaModelService {
         if(objectType == null) {
             return null;
         }
-        final ObjectSpecId objectSpecId = new ObjectSpecId(objectType);
+        final ObjectSpecId objectSpecId = ObjectSpecId.of(objectType);
         final ObjectSpecification objectSpecification = specificationLookup.lookupBySpecId(objectSpecId);
         return objectSpecification != null? objectSpecification.getCorrespondingClass(): null;
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecId.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecId.java
index 215b379..9a7f3a8 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecId.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecId.java
@@ -18,7 +18,10 @@
  */
 package org.apache.isis.core.metamodel.spec;
 
+import static org.apache.isis.commons.internal.base._With.requiresNotEmpty;
+
 import java.io.Serializable;
+import java.util.Objects;
 
 import org.apache.isis.core.metamodel.facets.object.objectspecid.ObjectSpecIdFacet;
 
@@ -36,11 +39,11 @@ public final class ObjectSpecId implements Serializable {
     private final String specId;
 
     public static ObjectSpecId of(String specId) {
+        requiresNotEmpty(specId, "specId");
         return new ObjectSpecId(specId);
     }
 
-    public ObjectSpecId(String specId) {
-        assert !(specId == null || "".equals(specId));
+    private ObjectSpecId(String specId) {
         this.specId = specId;
     }
 
@@ -50,27 +53,22 @@ public final class ObjectSpecId implements Serializable {
 
     @Override
     public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        result = prime * result + ((specId == null) ? 0 : specId.hashCode());
-        return result;
+        return specId.hashCode();
     }
 
     @Override
     public boolean equals(Object obj) {
-        if (this == obj)
+        if (this == obj) {
             return true;
-        if (obj == null)
-            return false;
-        if (getClass() != obj.getClass())
+        }
+        if (obj == null) {
             return false;
-        ObjectSpecId other = (ObjectSpecId) obj;
-        if (specId == null) {
-            if (other.specId != null)
-                return false;
-        } else if (!specId.equals(other.specId))
+        }
+        if (getClass() != obj.getClass()) {
             return false;
-        return true;
+        }
+        final ObjectSpecId other = (ObjectSpecId) obj;
+        return Objects.equals(specId, other.specId);
     }
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/standalonelist/ObjectSpecificationOnStandaloneList.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/standalonelist/ObjectSpecificationOnStandaloneList.java
index 1815814..262813f 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/standalonelist/ObjectSpecificationOnStandaloneList.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/standalonelist/ObjectSpecificationOnStandaloneList.java
@@ -52,7 +52,7 @@ public class ObjectSpecificationOnStandaloneList extends ObjectSpecificationAbst
             final ServicesInjector servicesInjector,
             final FacetProcessor facetProcessor) {
         super(FreeStandingList.class, NAME, servicesInjector, facetProcessor);
-        this.specId = new ObjectSpecId(getCorrespondingClass().getName());
+        this.specId = ObjectSpecId.of(getCorrespondingClass().getName());
     }
 
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/VersionTest_valueSemantics.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/VersionTest_valueSemantics.java
index 7eb0d42..0e3ecd1 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/VersionTest_valueSemantics.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/oid/VersionTest_valueSemantics.java
@@ -30,17 +30,17 @@ public class VersionTest_valueSemantics extends ValueTypeContractTestAbstract<Ve
     @Override
     protected List<Version> getObjectsWithSameValue() {
         return Arrays.asList(
-                    Version.create(123L, null, (Long)null), 
-                    Version.create(123L, "jimmy", (Long)null), 
-                    Version.create(123L, null, new Date().getTime())
+                    Version.of(123L, null), 
+                    Version.of(123L, "jimmy"), 
+                    Version.of(123L, null, new Date().getTime())
                 ); 
     }
 
     @Override
     protected List<Version> getObjectsWithDifferentValue() {
         return Arrays.asList(
-                    Version.create(124L, null, (Long)null), 
-                    Version.create(125L, null, (Long)null) 
+                    Version.of(124L, null), 
+                    Version.of(125L, null) 
                 );
     }
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/version/VersionTest_differs.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/version/VersionTest_differs.java
index d32b205..5daff40 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/version/VersionTest_differs.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/adapter/version/VersionTest_differs.java
@@ -29,19 +29,20 @@ public class VersionTest_differs {
 
     private Version version1, version2;
 
+    private final static String EMPTY_USERNAME = null;
 
     @Test
     public void whenEqual() throws Exception {
-        version1 = Version.create(123L);
-        version2 = Version.create(123L);
+        version1 = Version.of(123L, EMPTY_USERNAME);
+        version2 = Version.of(123L, EMPTY_USERNAME);
         assertThat(version1.different(version2), is(false));
     }
 
     
     @Test
     public void whenNotEqual() throws Exception {
-        version1 = Version.create(123L);
-        version2 = Version.create(124L);
+        version1 = Version.of(123L, EMPTY_USERNAME);
+        version2 = Version.of(124L, EMPTY_USERNAME);
         assertThat(version1.different(version2), is(true));
     }
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/spec/ObjectSpecIdTest_constructor.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/spec/ObjectSpecIdTest_constructor.java
index 1c92da6..3cc3e22 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/spec/ObjectSpecIdTest_constructor.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/spec/ObjectSpecIdTest_constructor.java
@@ -25,18 +25,18 @@ public class ObjectSpecIdTest_constructor {
     @Test
     public void happyCase() throws Exception {
         @SuppressWarnings("unused")
-        final ObjectSpecId objectSpecId = new ObjectSpecId("CUS");
+        final ObjectSpecId objectSpecId = ObjectSpecId.of("CUS");
     }
 
-    @Test(expected=AssertionError.class)
+    @Test(expected=IllegalArgumentException.class)
     public void cannotBeEmpty() throws Exception {
-        new ObjectSpecId("");
+        ObjectSpecId.of("");
     }
 
 
-    @Test(expected=AssertionError.class)
+    @Test(expected=NullPointerException.class)
     public void cannotBeNull() throws Exception {
-        new ObjectSpecId(null);
+        ObjectSpecId.of(null);
     }
 
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/spec/ObjectSpecIdTest_valueSemantics.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/spec/ObjectSpecIdTest_valueSemantics.java
index 58fd543..e324b16 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/spec/ObjectSpecIdTest_valueSemantics.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/spec/ObjectSpecIdTest_valueSemantics.java
@@ -27,12 +27,12 @@ public class ObjectSpecIdTest_valueSemantics extends ValueTypeContractTestAbstra
 
     @Override
     protected List<ObjectSpecId> getObjectsWithSameValue() {
-        return Arrays.asList(new ObjectSpecId("CUS"), new ObjectSpecId("CUS"), new ObjectSpecId("CUS"));
+        return Arrays.asList(ObjectSpecId.of("CUS"), ObjectSpecId.of("CUS"), ObjectSpecId.of("CUS"));
     }
 
     @Override
     protected List<ObjectSpecId> getObjectsWithDifferentValue() {
-        return Arrays.asList(new ObjectSpecId("bUS"), new ObjectSpecId("CUt"));
+        return Arrays.asList(ObjectSpecId.of("bUS"), ObjectSpecId.of("CUt"));
     }
 
 }
diff --git a/core/plugins/jdo-datanucleus-4/src/main/java/org/apache/isis/core/runtime/system/persistence/Utils.java b/core/plugins/jdo-datanucleus-4/src/main/java/org/apache/isis/core/runtime/system/persistence/Utils.java
index f4dc7f3..e67d993 100644
--- a/core/plugins/jdo-datanucleus-4/src/main/java/org/apache/isis/core/runtime/system/persistence/Utils.java
+++ b/core/plugins/jdo-datanucleus-4/src/main/java/org/apache/isis/core/runtime/system/persistence/Utils.java
@@ -19,7 +19,6 @@
 package org.apache.isis.core.runtime.system.persistence;
 
 import java.sql.Timestamp;
-import java.util.Date;
 
 import javax.jdo.listener.InstanceLifecycleEvent;
 
@@ -45,13 +44,17 @@ public class Utils {
         Object jdoVersion = pojo.dnGetVersion();
         if(jdoVersion instanceof Long) {
             final Long longVersion = (Long) jdoVersion;
-            return Version.create(longVersion, authenticationSession.getUserName(), (Date) null);
+            return Version.Factory.ifPresent(longVersion, authenticationSession.getUserName());
         }
         if(jdoVersion instanceof java.sql.Timestamp) {
             final Timestamp timestampVersion = (Timestamp) jdoVersion;
-            return Version.create(timestampVersion.getTime(), authenticationSession.getUserName(), (Date) null);
+            return Version.of(timestampVersion.getTime(), authenticationSession.getUserName());
         }
         return null;
+        
     }
+    
+    
+    
 
 }
diff --git a/core/plugins/jdo-datanucleus-5/src/main/java/org/apache/isis/core/runtime/system/persistence/Utils.java b/core/plugins/jdo-datanucleus-5/src/main/java/org/apache/isis/core/runtime/system/persistence/Utils.java
index f4dc7f3..cfa78ac 100644
--- a/core/plugins/jdo-datanucleus-5/src/main/java/org/apache/isis/core/runtime/system/persistence/Utils.java
+++ b/core/plugins/jdo-datanucleus-5/src/main/java/org/apache/isis/core/runtime/system/persistence/Utils.java
@@ -19,7 +19,6 @@
 package org.apache.isis.core.runtime.system.persistence;
 
 import java.sql.Timestamp;
-import java.util.Date;
 
 import javax.jdo.listener.InstanceLifecycleEvent;
 
@@ -45,13 +44,14 @@ public class Utils {
         Object jdoVersion = pojo.dnGetVersion();
         if(jdoVersion instanceof Long) {
             final Long longVersion = (Long) jdoVersion;
-            return Version.create(longVersion, authenticationSession.getUserName(), (Date) null);
+            return Version.Factory.ifPresent(longVersion, authenticationSession.getUserName());
         }
         if(jdoVersion instanceof java.sql.Timestamp) {
             final Timestamp timestampVersion = (Timestamp) jdoVersion;
-            return Version.create(timestampVersion.getTime(), authenticationSession.getUserName(), (Date) null);
+            return Version.of(timestampVersion.getTime(), authenticationSession.getUserName());
         }
         return null;
+        
     }
 
 }
diff --git a/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoder.java b/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoder.java
index 3b62562..42db859 100644
--- a/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoder.java
+++ b/core/viewer-restfulobjects-rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoder.java
@@ -73,7 +73,7 @@ public final class JsonValueEncoder {
 
         public List<ObjectSpecId> getSpecIds() {
             return _NullSafe.stream(classes)
-            .map((Class<?> cls) ->new ObjectSpecId(cls.getName()))
+            .map((Class<?> cls) ->ObjectSpecId.of(cls.getName()))
             .collect(Collectors.toList());
         }
 
diff --git a/core/viewer-restfulobjects-rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_appendValueAndFormat.java b/core/viewer-restfulobjects-rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_appendValueAndFormat.java
index af1e5ae..c9da18f 100644
--- a/core/viewer-restfulobjects-rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_appendValueAndFormat.java
+++ b/core/viewer-restfulobjects-rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_appendValueAndFormat.java
@@ -401,7 +401,7 @@ public class JsonValueEncoderTest_appendValueAndFormat {
         context.checking(new Expectations() {
             {
                 oneOf(mockObjectSpec).getSpecId();
-                will(returnValue(new ObjectSpecId(cls.getName())));
+                will(returnValue(ObjectSpecId.of(cls.getName())));
             }
         });
     }
diff --git a/core/viewer-restfulobjects-rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asObject.java b/core/viewer-restfulobjects-rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asObject.java
index 14fb6c3..6b3aa98 100644
--- a/core/viewer-restfulobjects-rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asObject.java
+++ b/core/viewer-restfulobjects-rendering/src/test/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/JsonValueEncoderTest_asObject.java
@@ -229,7 +229,7 @@ public class JsonValueEncoderTest_asObject {
         context.checking(new Expectations() {
             {
                 allowing(mockObjectSpec).getSpecId();
-                will(returnValue(new ObjectSpecId(result.getName())));
+                will(returnValue(ObjectSpecId.of(result.getName())));
             }
         });
     }