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 2020/01/17 09:39:07 UTC

[isis] branch master updated: ISIS-2158: remove DtoMappingHelper, and a subclass of Bookmark ...

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 48d2c6b  ISIS-2158: remove DtoMappingHelper, and a subclass of Bookmark ...
48d2c6b is described below

commit 48d2c6b445605429150988803b161b7a717a7890
Author: Andi Huber <ah...@apache.org>
AuthorDate: Fri Jan 17 10:38:51 2020 +0100

    ISIS-2158: remove DtoMappingHelper, and a subclass of Bookmark ...
    
    also remove from OidDto:
    
    @XmlElement(required = true)
    protected String objectType;
    
    @XmlElement(required = true)
    protected String objectIdentifier;
---
 .../org/apache/isis/applib/IsisModuleApplib.java   |   2 -
 .../isis/applib/mixins/dto/DtoMappingHelper.java   |  61 ---
 .../isis/applib/services/bookmark/Bookmark.java    | 106 ++---
 .../isis/applib/services/hint/HintStore.java       |  23 --
 .../applib/services/urlencoding/MementosTest.java  |   4 +-
 ...eractionDtoUtilsTest_deriveLogicalMemberId.java |   2 +-
 .../apache/isis/applib/util/schema/Roundtrip.java  |   4 +-
 .../org/apache/isis/schema/common/common-2.0.xsd   | 460 ++++++++++-----------
 .../isis/core/commons/internal/base/_Strings.java  |  14 +-
 .../internal/base/_Strings_KeyValuePair.java       |  12 +-
 .../isis/core/metamodel/adapter/oid/Oid_Root.java  |   2 +-
 .../transaction/AdapterAndProperty.java            |   2 +-
 .../bookmarks/BookmarkServiceInternalDefault.java  |   2 +-
 .../pdfjs/applib/spi/PdfJsViewerAdvisor.java       |  13 +-
 .../excel/applib/dom/util/CellMarshaller.java      |   2 +-
 .../applib/fixturescripts/FixtureResult.java       |   2 +-
 .../wicket/ui/panels/FormExecutorDefault.java      |  30 +-
 .../services/HintStoreUsingWicketSession.java      |  12 +-
 .../services/mementos/ObjectMementoLegacy.java     |   2 +-
 19 files changed, 312 insertions(+), 443 deletions(-)

diff --git a/api/applib/src/main/java/org/apache/isis/applib/IsisModuleApplib.java b/api/applib/src/main/java/org/apache/isis/applib/IsisModuleApplib.java
index ac13ffc..3c5f98e 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/IsisModuleApplib.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/IsisModuleApplib.java
@@ -21,7 +21,6 @@ package org.apache.isis.applib;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Import;
 
-import org.apache.isis.applib.mixins.dto.DtoMappingHelper;
 import org.apache.isis.applib.mixins.dto.Dto_downloadXml;
 import org.apache.isis.applib.mixins.dto.Dto_downloadXsd;
 import org.apache.isis.applib.mixins.layout.Object_downloadLayoutXml;
@@ -77,7 +76,6 @@ import org.apache.isis.schema.IsisModuleSchema;
         CommandContext.class,
         ContentMappingServiceForCommandDto.class,
         ContentMappingServiceForCommandsDto.class,
-        DtoMappingHelper.class,
         InteractionContext.class,
         JaxbServiceDefault.class,
         PublisherServiceLogging.class,
diff --git a/api/applib/src/main/java/org/apache/isis/applib/mixins/dto/DtoMappingHelper.java b/api/applib/src/main/java/org/apache/isis/applib/mixins/dto/DtoMappingHelper.java
deleted file mode 100644
index 66dd803..0000000
--- a/api/applib/src/main/java/org/apache/isis/applib/mixins/dto/DtoMappingHelper.java
+++ /dev/null
@@ -1,61 +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.isis.applib.mixins.dto;
-
-import javax.inject.Inject;
-import javax.inject.Named;
-
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.context.annotation.Primary;
-import org.springframework.core.annotation.Order;
-import org.springframework.stereotype.Service;
-
-import org.apache.isis.applib.annotation.OrderPrecedence;
-import org.apache.isis.applib.services.bookmark.Bookmark;
-import org.apache.isis.applib.services.bookmark.BookmarkService;
-import org.apache.isis.schema.common.v2.OidDto;
-
-@Service
-@Named("isisApplib.DtoMappingHelper")
-@Order(OrderPrecedence.MIDPOINT)
-@Primary
-@Qualifier("Default")
-public class DtoMappingHelper {
-    
-    @Inject private BookmarkService bookmarkService;
-
-    public OidDto oidDtoFor(final Object object) {
-        final Bookmark bookmark = bookmarkService.bookmarkFor(object);
-        return asOidDto(bookmark);
-    }
-
-    private static OidDto asOidDto(final Bookmark reference) {
-        OidDto argValue;
-        if (reference != null) {
-            argValue = new OidDto();
-            argValue.setObjectType(reference.getObjectType());
-            argValue.setObjectIdentifier(reference.getIdentifier());
-        } else {
-            argValue = null;
-        }
-        return argValue;
-    }
-
-    
-}
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/bookmark/Bookmark.java b/api/applib/src/main/java/org/apache/isis/applib/services/bookmark/Bookmark.java
index cc31cbc..c9bbe83 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/bookmark/Bookmark.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/bookmark/Bookmark.java
@@ -19,109 +19,87 @@
 package org.apache.isis.applib.services.bookmark;
 
 import java.io.Serializable;
-import java.util.Iterator;
-import java.util.Objects;
+import java.util.Optional;
+import java.util.StringTokenizer;
+
+import javax.annotation.Nullable;
 
 import org.apache.isis.applib.annotation.Value;
-import org.apache.isis.core.commons.internal.base._Strings;
 import org.apache.isis.schema.common.v2.OidDto;
 
-import lombok.Getter;
+import lombok.NonNull;
+import lombok.RequiredArgsConstructor;
 import lombok.val;
 
 /**
- * String representation of any persistent object managed by the framework.
+ * String representation of any persistable or re-createable object managed by the framework.
  *
  * <p>
  * Analogous to the <tt>RootOid</tt>.
  */
-@Value
+@Value @lombok.Value @RequiredArgsConstructor
 public class Bookmark implements Serializable {
 
-    private static final long serialVersionUID = 1L;
+    private static final long serialVersionUID = 2L;
 
     protected static final String SEPARATOR = ":";
     
-    @Getter private final String objectType;
-    @Getter private final String identifier;
-
+    @NonNull  private final String objectType;
+    @NonNull  private final String identifier;
+    @Nullable private final String hintId;
 
-    public static Bookmark create(String str) {
-        return str != null? new Bookmark(str): null;
+    public static Bookmark of(String objectType, String identifier) {
+        return new Bookmark(objectType, identifier, /*hintId*/ null);
     }
-
-    public OidDto toOidDto() {
-        final OidDto oidDto = new OidDto();
-
-        oidDto.setType(getObjectType());
-        oidDto.setId(getIdentifier());
-
-        return oidDto;
-    }
-
-    public static Bookmark from(OidDto oidDto) {
-        val objectType = coalesce(oidDto.getType(), oidDto.getObjectType());
-        val objectId = coalesce(oidDto.getId(), oidDto.getObjectIdentifier());
-        val bookmark = new Bookmark(objectType, objectId);
-        return bookmark;
-    }
-
+    
     /**
      * Round-trip with {@link #toString()} representation.
      */
-    public Bookmark(final String toString) {
-        this(_Strings.splitThenStream(toString, SEPARATOR).iterator());
-    }
-
-    private Bookmark(final Iterator<String> split) {
-        this(split.next(), split.next());
-    }
+    public static Optional<Bookmark> parse(@Nullable String str) {
+        if(str==null) {
+            return Optional.empty();
+        }
+        val tokenizer = new StringTokenizer(str, SEPARATOR);
+        int tokenCount = tokenizer.countTokens();
+        if(tokenCount>1) {
+            return Optional.of(Bookmark.of(tokenizer.nextToken(), tokenizer.nextToken()));            
+        }
+        return Optional.empty();
 
-    public Bookmark(final String objectType, final String identifier) {
-        this.objectType = objectType;
-        this.identifier = identifier;
     }
 
-    @Override
-    public int hashCode() {
-        return Objects.hash(this.getIdentifier(), this.getObjectType());
+    public OidDto toOidDto() {
+        val oidDto = new OidDto();
+        oidDto.setType(getObjectType());
+        oidDto.setId(getIdentifier());
+        return oidDto;
     }
 
-    @Override
-    public boolean equals(final Object obj) {
-        if (this == obj) return true;
-        if (obj == null) return false;
-        if (this.getClass() != obj.getClass()) return false;
-        
-        val other = (Bookmark) obj;
-        
-        if(! Objects.equals(this.identifier, other.identifier)) {
-            return false;
-        }
-        if(! Objects.equals(this.objectType, other.objectType)) {
-            return false;
-        }
-        
-        return true;
+    public static Bookmark from(@NonNull OidDto oidDto) {
+        return Bookmark.of(oidDto.getType(), oidDto.getId());
     }
-
+    
     /**
-     * The canonical form of the {@link Bookmark}, that is &quot;{@link #getObjectType() objectType}{@value #SEPARATOR}{@link #getIdentifier()}&quot;.
+     * The canonical form of the {@link Bookmark}, that is 
+     * &quot;{@link #getObjectType() objectType}{@value #SEPARATOR}{@link #getIdentifier()}&quot;.
      *
      * <p>
-     * This is parseable by the {@link #Bookmark(String) string constructor}.
+     * This is parseable by the {@link #parse(String)}.
      */
     @Override
     public String toString() {
         return objectType + SEPARATOR + identifier;
     }
 
-    // -- HELPER
+    // -- HINT-ID EXTENSION
     
-    private static String coalesce(final String first, final String second) {
-        return first != null? first: second;
+    public Bookmark withHintId(@NonNull String hintId) {
+        return new Bookmark(this.getObjectType(), this.getIdentifier(), hintId); 
     }
 
+    public String toStringUsingIdentifier(String id) {
+        return objectType + SEPARATOR + id;
+    }
     
 
 }
diff --git a/api/applib/src/main/java/org/apache/isis/applib/services/hint/HintStore.java b/api/applib/src/main/java/org/apache/isis/applib/services/hint/HintStore.java
index 728e7d4..5aa5bed 100644
--- a/api/applib/src/main/java/org/apache/isis/applib/services/hint/HintStore.java
+++ b/api/applib/src/main/java/org/apache/isis/applib/services/hint/HintStore.java
@@ -23,32 +23,9 @@ import java.util.Set;
 import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 
-import lombok.Getter;
-
 @Programmatic
 public interface HintStore {
 
-    public static class BookmarkWithHintId extends Bookmark {
-
-        private static final long serialVersionUID = -459431279406553124L;
-
-        @Getter private final String hintId;
-
-        public BookmarkWithHintId(final Bookmark bookmark, final String hintId) {
-            super(bookmark.toString());
-            this.hintId = hintId;
-        }
-
-        /**
-         * Similar to {@link #toString()}, but using {@link #hintId} rather than {@link #identifier}.
-         */
-        public String toStringUsingHintId() {
-            return super.getObjectType() 
-                    + SEPARATOR 
-                    + hintId;
-        }
-    }
-
     interface HintIdProvider {
         String hintId();
     }
diff --git a/api/applib/src/test/java/org/apache/isis/applib/services/urlencoding/MementosTest.java b/api/applib/src/test/java/org/apache/isis/applib/services/urlencoding/MementosTest.java
index f426698..76f3e8b 100644
--- a/api/applib/src/test/java/org/apache/isis/applib/services/urlencoding/MementosTest.java
+++ b/api/applib/src/test/java/org/apache/isis/applib/services/urlencoding/MementosTest.java
@@ -96,7 +96,7 @@ public class MementosTest {
         memento.put("someLocalDate", LocalDate.of(2013,9,3));
         memento.put("someJavaUtilDate", new Date(300_000_000));
 
-        memento.put("someBookmark", new Bookmark("CUS", "12345"));
+        memento.put("someBookmark", Bookmark.of("CUS", "12345"));
         memento.put("someNullValue", null);
 
         memento.put("someEnum", DOW.Wed);
@@ -119,7 +119,7 @@ public class MementosTest {
         assertThat(memento2.get("someBigDecimal", BigDecimal.class), is(new BigDecimal("123456789012345678901234567890.123456789")));
         assertThat(memento2.get("someLocalDate", LocalDate.class), is(LocalDate.of(2013,9,3)));
         assertThat(memento2.get("someJavaUtilDate", Date.class), is(new Date(300_000_000)));
-        assertThat(memento2.get("someBookmark", Bookmark.class), is(new Bookmark("CUS", "12345")));
+        assertThat(memento2.get("someBookmark", Bookmark.class), is(Bookmark.of("CUS", "12345")));
 
         // a nullValue can be grabbed as any type, will always succeed
         assertThat(memento2.get("someNullValue", Integer.class), is(nullValue()));
diff --git a/api/applib/src/test/java/org/apache/isis/applib/util/schema/InteractionDtoUtilsTest_deriveLogicalMemberId.java b/api/applib/src/test/java/org/apache/isis/applib/util/schema/InteractionDtoUtilsTest_deriveLogicalMemberId.java
index 0e4b653..11239e3 100644
--- a/api/applib/src/test/java/org/apache/isis/applib/util/schema/InteractionDtoUtilsTest_deriveLogicalMemberId.java
+++ b/api/applib/src/test/java/org/apache/isis/applib/util/schema/InteractionDtoUtilsTest_deriveLogicalMemberId.java
@@ -28,7 +28,7 @@ public class InteractionDtoUtilsTest_deriveLogicalMemberId {
 
     @Test
     public void happy_case() throws Exception {
-        String s = InteractionDtoUtils.deriveLogicalMemberId(new Bookmark("customer.Order", "1234"),
+        String s = InteractionDtoUtils.deriveLogicalMemberId(Bookmark.of("customer.Order", "1234"),
                 "com.mycompany.customer.Order#placeOrder");
         assertThat(s, is(equalTo("customer.Order#placeOrder")));
     }
diff --git a/api/applib/src/test/java/org/apache/isis/applib/util/schema/Roundtrip.java b/api/applib/src/test/java/org/apache/isis/applib/util/schema/Roundtrip.java
index f6c969d..b2b99a0 100644
--- a/api/applib/src/test/java/org/apache/isis/applib/util/schema/Roundtrip.java
+++ b/api/applib/src/test/java/org/apache/isis/applib/util/schema/Roundtrip.java
@@ -137,7 +137,7 @@ public class Roundtrip {
     
     private static class SampleValues {
         
-        final Bookmark bookmark = new Bookmark("ORD", "12345");
+        final Bookmark bookmark = Bookmark.of("ORD", "12345");
         final OidDto reference = new OidDto();
         {
             reference.setId("12345");
@@ -192,7 +192,7 @@ public class Roundtrip {
         final InteractionDto interactionDto = newInteractionDtoWithActionInvocation(
                 UUID.randomUUID().toString(),
                 1,
-                new Bookmark("CUS", "12345"), "John Customer", "com.mycompany.Customer#placeOrder", Arrays.<ParamDto>asList(),
+                Bookmark.of("CUS", "12345"), "John Customer", "com.mycompany.Customer#placeOrder", Arrays.<ParamDto>asList(),
                 "freddyUser"
                 );
         
diff --git a/api/schema/src/main/resources/org/apache/isis/schema/common/common-2.0.xsd b/api/schema/src/main/resources/org/apache/isis/schema/common/common-2.0.xsd
index d36a0ba..ed9a656 100644
--- a/api/schema/src/main/resources/org/apache/isis/schema/common/common-2.0.xsd
+++ b/api/schema/src/main/resources/org/apache/isis/schema/common/common-2.0.xsd
@@ -1,238 +1,226 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-  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.
--->
-<xs:schema targetNamespace="http://isis.apache.org/schema/common"
-           elementFormDefault="qualified"
-           xmlns="http://isis.apache.org/schema/common"
-           xmlns:xs="http://www.w3.org/2001/XMLSchema">
-
-    <xs:complexType name="valueDto">
-        <xs:choice minOccurs="0" maxOccurs="1">
-            <xs:element name="string" type="xs:string"/>
-            <xs:element name="byte" type="xs:byte"/>
-            <xs:element name="short" type="xs:short"/>
-            <xs:element name="int" type="xs:int"/>
-            <xs:element name="long" type="xs:long"/>
-            <xs:element name="float" type="xs:float"/>
-            <xs:element name="double" type="xs:double"/>
-            <xs:element name="boolean" type="xs:boolean"/>
-            <xs:element name="char" type="xs:string"/>
-            <xs:element name="bigInteger" type="xs:integer"/>
-            <xs:element name="bigDecimal" type="xs:decimal"/>
-            <!-- java.time -->
-            <xs:element name="localDate" type="xs:date"/>
-            <xs:element name="localDateTime" type="xs:dateTime"/>
-            <xs:element name="localTime" type="xs:time"/>
-            <xs:element name="offsetTime" type="xs:time"/>
-            <xs:element name="offsetDateTime" type="xs:dateTime"/>
-            <xs:element name="zonedDateTime" type="xs:dateTime"/>
-            <!-- joda -->
-            <xs:element name="jodaDateTime" type="xs:dateTime"/>
-            <xs:element name="jodaLocalDate" type="xs:date"/>
-            <xs:element name="jodaLocalTime" type="xs:time"/>
-            <xs:element name="jodaLocalDateTime" type="xs:dateTime"/>
-            <!--  -->
-            <xs:element name="timestamp" type="xs:dateTime"/>
-            <xs:element name="enum" type="enumDto"/>
-            <xs:element name="reference" type="oidDto"/>
-            <xs:element name="collection" type="collectionDto"/>
-            <xs:element name="blob" type="blobDto"/>
-            <xs:element name="clob" type="clobDto"/>
-        </xs:choice>
-    </xs:complexType>
-
-    <xs:complexType name="oidDto">
-        <xs:sequence>
-            <xs:element name="objectType" type="xs:string">
-                <xs:annotation>
-                    <xs:documentation>Deprecated, use the 'objectType' attribute instead.</xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="objectIdentifier" type="xs:string">
-                <xs:annotation>
-                    <xs:documentation>Deprecated, use the 'id' attribute instead.</xs:documentation>
-                </xs:annotation>
-            </xs:element>
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<xs:schema targetNamespace="http://isis.apache.org/schema/common"
+           elementFormDefault="qualified"
+           xmlns="http://isis.apache.org/schema/common"
+           xmlns:xs="http://www.w3.org/2001/XMLSchema">
+
+    <xs:complexType name="valueDto">
+        <xs:choice minOccurs="0" maxOccurs="1">
+            <xs:element name="string" type="xs:string"/>
+            <xs:element name="byte" type="xs:byte"/>
+            <xs:element name="short" type="xs:short"/>
+            <xs:element name="int" type="xs:int"/>
+            <xs:element name="long" type="xs:long"/>
+            <xs:element name="float" type="xs:float"/>
+            <xs:element name="double" type="xs:double"/>
+            <xs:element name="boolean" type="xs:boolean"/>
+            <xs:element name="char" type="xs:string"/>
+            <xs:element name="bigInteger" type="xs:integer"/>
+            <xs:element name="bigDecimal" type="xs:decimal"/>
+            <!-- java.time -->
+            <xs:element name="localDate" type="xs:date"/>
+            <xs:element name="localDateTime" type="xs:dateTime"/>
+            <xs:element name="localTime" type="xs:time"/>
+            <xs:element name="offsetTime" type="xs:time"/>
+            <xs:element name="offsetDateTime" type="xs:dateTime"/>
+            <xs:element name="zonedDateTime" type="xs:dateTime"/>
+            <!-- joda -->
+            <xs:element name="jodaDateTime" type="xs:dateTime"/>
+            <xs:element name="jodaLocalDate" type="xs:date"/>
+            <xs:element name="jodaLocalTime" type="xs:time"/>
+            <xs:element name="jodaLocalDateTime" type="xs:dateTime"/>
+            <!--  -->
+            <xs:element name="timestamp" type="xs:dateTime"/>
+            <xs:element name="enum" type="enumDto"/>
+            <xs:element name="reference" type="oidDto"/>
+            <xs:element name="collection" type="collectionDto"/>
+            <xs:element name="blob" type="blobDto"/>
+            <xs:element name="clob" type="clobDto"/>
+        </xs:choice>
+    </xs:complexType>
+
+    <xs:complexType name="oidDto">
+        <xs:attribute name="type" type="xs:string"/>
+        <xs:attribute name="id" type="xs:string"/>
+    </xs:complexType>
+
+    <xs:complexType name="collectionDto">
+        <xs:annotation>
+            <xs:documentation>A collection of (argument) values
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="value" type="valueDto" minOccurs="1" maxOccurs="unbounded"/>
         </xs:sequence>
-        <xs:attribute name="type" type="xs:string"/>
-        <xs:attribute name="id" type="xs:string"/>
-    </xs:complexType>
-
-    <xs:complexType name="collectionDto">
-        <xs:annotation>
-            <xs:documentation>A collection of (argument) values
-            </xs:documentation>
-        </xs:annotation>
-        <xs:sequence>
-            <xs:element name="value" type="valueDto" minOccurs="1" maxOccurs="unbounded"/>
-        </xs:sequence>
-        <xs:attribute name="type" use="required" type="valueType"/>
-        <xs:attribute name="null" use="optional" type="xs:boolean"/>
-    </xs:complexType>
-
-    <xs:complexType name="blobDto">
-        <xs:annotation>
-            <xs:documentation>A collection of (argument) values
-            </xs:documentation>
-        </xs:annotation>
-        <xs:sequence>
-            <xs:element name="name" type="xs:string"/>
-            <xs:element name="mimeType" type="xs:string"/>
-            <xs:element name="bytes" type="xs:hexBinary"/>
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="clobDto">
-        <xs:annotation>
-            <xs:documentation>A collection of (argument) values
-            </xs:documentation>
-        </xs:annotation>
-        <xs:sequence>
-            <xs:element name="name" type="xs:string"/>
-            <xs:element name="mimeType" type="xs:string"/>
-            <xs:element name="chars" type="xs:string"/>
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="oidsDto">
-        <xs:annotation>
-            <xs:documentation>A list of OIDs
-            </xs:documentation>
-        </xs:annotation>
-        <xs:sequence>
-            <xs:element name="oid" type="oidDto" minOccurs="1" maxOccurs="unbounded"/>
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="enumDto">
-        <xs:sequence>
-            <xs:element name="enumType" type="xs:string"/>
-            <xs:element name="enumName" type="xs:string"/>
-        </xs:sequence>
-    </xs:complexType>
-
-
-    <xs:simpleType name="valueType">
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="string"/>
-            <xs:enumeration value="byte"/>
-            <xs:enumeration value="short"/>
-            <xs:enumeration value="int"/>
-            <xs:enumeration value="long"/>
-            <xs:enumeration value="float"/>
-            <xs:enumeration value="double"/>
-            <xs:enumeration value="boolean"/>
-            <xs:enumeration value="char"/>
-            <xs:enumeration value="bigInteger"/>
-            <xs:enumeration value="bigDecimal"/>
-            <xs:enumeration value="javaSqlTimestamp"/>
-            <!-- java.time -->
-            <xs:enumeration value="localDateTime"/>
-            <xs:enumeration value="localDate"/>
-            <xs:enumeration value="localTime"/>
-            <xs:enumeration value="offsetDateTime"/>
-            <xs:enumeration value="offsetTime"/>
-            <xs:enumeration value="zonedDateTime"/>
-            <!-- joda -->
-            <xs:enumeration value="jodaDateTime"/>
-            <xs:enumeration value="jodaLocalDate"/>
-            <xs:enumeration value="jodaLocalTime"/>
-            <xs:enumeration value="jodaLocalDateTime"/>
-            <!--  -->
-            <xs:enumeration value="enum"/>
-            <xs:enumeration value="reference"/>
-            <xs:enumeration value="collection"/>
-            <xs:enumeration value="blob"/>
-            <xs:enumeration value="clob"/>
-            <xs:enumeration value="void">
-                <xs:annotation>
-                    <xs:documentation>Not valid to be used as the parameter type of an action; can be used as its return type.
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:enumeration>
-        </xs:restriction>
-    </xs:simpleType>
-
-    <xs:complexType name="periodDto">
-        <xs:annotation>
-            <xs:documentation>Captures a period of time, eg for capturing metrics/timings.
-            </xs:documentation>
-        </xs:annotation>
-        <xs:sequence>
-            <xs:element name="startedAt" type="xs:dateTime">
-                <xs:annotation>
-                    <xs:documentation>The point in time that this period of time started.
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:element>
-            <xs:element name="completedAt" type="xs:dateTime" minOccurs="0" maxOccurs="1">
-                <xs:annotation>
-                    <xs:documentation>The point in time that this period of time completed.  The duration is the difference between 'start' and 'complete'.
-                    </xs:documentation>
-                </xs:annotation>
-            </xs:element>
-        </xs:sequence>
-    </xs:complexType>
-
-    <xs:complexType name="differenceDto">
-        <xs:annotation>
-            <xs:documentation>Captures a pair of numbers representing a difference.  Used for example to capture metrics (number objects modified before and after).
-            </xs:documentation>
-        </xs:annotation>
-        <xs:sequence>
-        </xs:sequence>
-        <xs:attribute name="before" type="xs:int">
-            <xs:annotation>
-                <xs:documentation>The initial quantity.
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-        <xs:attribute name="after" type="xs:int">
-            <xs:annotation>
-                <xs:documentation>The final quantity, once known.  The difference is therefore the computation of (after - before).
-                </xs:documentation>
-            </xs:annotation>
-        </xs:attribute>
-    </xs:complexType>
-
-    <xs:complexType name="valueWithTypeDto">
-        <xs:annotation>
-            <xs:documentation>Captures both a value and its corresponding type.  Used for the return value of action invocations, and for the new value in property edits.
-            </xs:documentation>
-        </xs:annotation>
-        <xs:complexContent>
-            <xs:extension base="valueDto">
-                <xs:attribute name="type" use="required" type="valueType"/>
-                <xs:attribute name="null" use="optional" type="xs:boolean"/>
-            </xs:extension>
-        </xs:complexContent>
-    </xs:complexType>
-
-
-    <xs:simpleType name="interactionType" >
-        <xs:annotation>
-            <xs:documentation>Whether this interaction with a member is invoking an action, or editing a property.</xs:documentation>
-        </xs:annotation>
-        <xs:restriction base="xs:string">
-            <xs:enumeration value="action_invocation" />
-            <xs:enumeration value="property_edit" />
-        </xs:restriction>
-    </xs:simpleType>
-
+        <xs:attribute name="type" use="required" type="valueType"/>
+        <xs:attribute name="null" use="optional" type="xs:boolean"/>
+    </xs:complexType>
+
+    <xs:complexType name="blobDto">
+        <xs:annotation>
+            <xs:documentation>A collection of (argument) values
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="name" type="xs:string"/>
+            <xs:element name="mimeType" type="xs:string"/>
+            <xs:element name="bytes" type="xs:hexBinary"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="clobDto">
+        <xs:annotation>
+            <xs:documentation>A collection of (argument) values
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="name" type="xs:string"/>
+            <xs:element name="mimeType" type="xs:string"/>
+            <xs:element name="chars" type="xs:string"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="oidsDto">
+        <xs:annotation>
+            <xs:documentation>A list of OIDs
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="oid" type="oidDto" minOccurs="1" maxOccurs="unbounded"/>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="enumDto">
+        <xs:sequence>
+            <xs:element name="enumType" type="xs:string"/>
+            <xs:element name="enumName" type="xs:string"/>
+        </xs:sequence>
+    </xs:complexType>
+
+
+    <xs:simpleType name="valueType">
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="string"/>
+            <xs:enumeration value="byte"/>
+            <xs:enumeration value="short"/>
+            <xs:enumeration value="int"/>
+            <xs:enumeration value="long"/>
+            <xs:enumeration value="float"/>
+            <xs:enumeration value="double"/>
+            <xs:enumeration value="boolean"/>
+            <xs:enumeration value="char"/>
+            <xs:enumeration value="bigInteger"/>
+            <xs:enumeration value="bigDecimal"/>
+            <xs:enumeration value="javaSqlTimestamp"/>
+            <!-- java.time -->
+            <xs:enumeration value="localDateTime"/>
+            <xs:enumeration value="localDate"/>
+            <xs:enumeration value="localTime"/>
+            <xs:enumeration value="offsetDateTime"/>
+            <xs:enumeration value="offsetTime"/>
+            <xs:enumeration value="zonedDateTime"/>
+            <!-- joda -->
+            <xs:enumeration value="jodaDateTime"/>
+            <xs:enumeration value="jodaLocalDate"/>
+            <xs:enumeration value="jodaLocalTime"/>
+            <xs:enumeration value="jodaLocalDateTime"/>
+            <!--  -->
+            <xs:enumeration value="enum"/>
+            <xs:enumeration value="reference"/>
+            <xs:enumeration value="collection"/>
+            <xs:enumeration value="blob"/>
+            <xs:enumeration value="clob"/>
+            <xs:enumeration value="void">
+                <xs:annotation>
+                    <xs:documentation>Not valid to be used as the parameter type of an action; can be used as its return type.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:enumeration>
+        </xs:restriction>
+    </xs:simpleType>
+
+    <xs:complexType name="periodDto">
+        <xs:annotation>
+            <xs:documentation>Captures a period of time, eg for capturing metrics/timings.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+            <xs:element name="startedAt" type="xs:dateTime">
+                <xs:annotation>
+                    <xs:documentation>The point in time that this period of time started.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+            <xs:element name="completedAt" type="xs:dateTime" minOccurs="0" maxOccurs="1">
+                <xs:annotation>
+                    <xs:documentation>The point in time that this period of time completed.  The duration is the difference between 'start' and 'complete'.
+                    </xs:documentation>
+                </xs:annotation>
+            </xs:element>
+        </xs:sequence>
+    </xs:complexType>
+
+    <xs:complexType name="differenceDto">
+        <xs:annotation>
+            <xs:documentation>Captures a pair of numbers representing a difference.  Used for example to capture metrics (number objects modified before and after).
+            </xs:documentation>
+        </xs:annotation>
+        <xs:sequence>
+        </xs:sequence>
+        <xs:attribute name="before" type="xs:int">
+            <xs:annotation>
+                <xs:documentation>The initial quantity.
+                </xs:documentation>
+            </xs:annotation>
+        </xs:attribute>
+        <xs:attribute name="after" type="xs:int">
+            <xs:annotation>
+                <xs:documentation>The final quantity, once known.  The difference is therefore the computation of (after - before).
+                </xs:documentation>
+            </xs:annotation>
+        </xs:attribute>
+    </xs:complexType>
+
+    <xs:complexType name="valueWithTypeDto">
+        <xs:annotation>
+            <xs:documentation>Captures both a value and its corresponding type.  Used for the return value of action invocations, and for the new value in property edits.
+            </xs:documentation>
+        </xs:annotation>
+        <xs:complexContent>
+            <xs:extension base="valueDto">
+                <xs:attribute name="type" use="required" type="valueType"/>
+                <xs:attribute name="null" use="optional" type="xs:boolean"/>
+            </xs:extension>
+        </xs:complexContent>
+    </xs:complexType>
+
+
+    <xs:simpleType name="interactionType" >
+        <xs:annotation>
+            <xs:documentation>Whether this interaction with a member is invoking an action, or editing a property.</xs:documentation>
+        </xs:annotation>
+        <xs:restriction base="xs:string">
+            <xs:enumeration value="action_invocation" />
+            <xs:enumeration value="property_edit" />
+        </xs:restriction>
+    </xs:simpleType>
+
 </xs:schema>
\ No newline at end of file
diff --git a/core/commons/src/main/java/org/apache/isis/core/commons/internal/base/_Strings.java b/core/commons/src/main/java/org/apache/isis/core/commons/internal/base/_Strings.java
index 8b65414..151870d 100644
--- a/core/commons/src/main/java/org/apache/isis/core/commons/internal/base/_Strings.java
+++ b/core/commons/src/main/java/org/apache/isis/core/commons/internal/base/_Strings.java
@@ -88,14 +88,16 @@ public final class _Strings {
     }
 
     /**
-     * Parses a string assumed to be of the form <kbd>key=value</kbd> into its parts.
-     *
-     * @return a non-empty Optional, if (and only if) the {@code keyValueLiteral} does contain at least one '='
+     * Parses a string assumed to be of the form <kbd>key[separator]value</kbd> into its parts.
+     * @param keyValueLiteral
+     * @param separator
+     * @return a non-empty Optional, if (and only if) the {@code keyValueLiteral} 
+     * does contain at least one {@code separator}
      */
-    public static Optional<KeyValuePair> parseKeyValuePair(@Nullable String keyValueLiteral) {
-        return _Strings_KeyValuePair.parse(keyValueLiteral);
+    public static Optional<KeyValuePair> parseKeyValuePair(@Nullable String keyValueLiteral, char separator) {
+        return _Strings_KeyValuePair.parse(keyValueLiteral, separator);
     }
-
+    
     // -- FILLING
 
     public static String of(int length, char c) {
diff --git a/core/commons/src/main/java/org/apache/isis/core/commons/internal/base/_Strings_KeyValuePair.java b/core/commons/src/main/java/org/apache/isis/core/commons/internal/base/_Strings_KeyValuePair.java
index 6abe6a6..4767c86 100644
--- a/core/commons/src/main/java/org/apache/isis/core/commons/internal/base/_Strings_KeyValuePair.java
+++ b/core/commons/src/main/java/org/apache/isis/core/commons/internal/base/_Strings_KeyValuePair.java
@@ -58,17 +58,19 @@ final class _Strings_KeyValuePair implements _Strings.KeyValuePair {
     }
 
     /**
-     * Parses a string assumed to be of the form <kbd>key=value</kbd> into its parts.
-     *
-     * @return a non-empty Optional, if (and only if) the {@code keyValueLiteral} does contain at least one '='
+     * Parses a string assumed to be of the form <kbd>key[separator]value</kbd> into its parts.
+     * @param keyValueLiteral
+     * @param separator
+     * @return a non-empty Optional, if (and only if) the {@code keyValueLiteral} 
+     * does contain at least one {@code separator}
      */
-    public static Optional<_Strings.KeyValuePair> parse(String keyValueLiteral) {
+    public static Optional<_Strings.KeyValuePair> parse(String keyValueLiteral, char separator) {
 
         if(_Strings.isNullOrEmpty(keyValueLiteral)) {
             return Optional.empty();
         }
 
-        final int equalsIndex = keyValueLiteral.indexOf('=');
+        final int equalsIndex = keyValueLiteral.indexOf(separator);
         if (equalsIndex == -1) {
             return Optional.empty();
         }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Root.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Root.java
index 42036f7..dc027c9 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Root.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/adapter/oid/Oid_Root.java
@@ -86,7 +86,7 @@ final class Oid_Root implements RootOid {
     public Bookmark asBookmark() {
         val objectType = getObjectSpecId().asString();
         val identifier = getIdentifier();
-        return new Bookmark(objectType, identifier);
+        return Bookmark.of(objectType, identifier);
     }
 
     @Override
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/transaction/AdapterAndProperty.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/transaction/AdapterAndProperty.java
index 0f70227..4b10695 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/transaction/AdapterAndProperty.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/persistence/transaction/AdapterAndProperty.java
@@ -48,7 +48,7 @@ public class AdapterAndProperty {
 
         final String objectType = oid.getObjectSpecId().asString();
         final String identifier = oid.getIdentifier();
-        bookmark = new Bookmark(objectType, identifier);
+        bookmark = Bookmark.of(objectType, identifier);
         bookmarkStr = bookmark.toString();
 
         propertyId = property.getId();
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/bookmarks/BookmarkServiceInternalDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/bookmarks/BookmarkServiceInternalDefault.java
index 7467b23..f3d8d6a 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/bookmarks/BookmarkServiceInternalDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/bookmarks/BookmarkServiceInternalDefault.java
@@ -156,7 +156,7 @@ public class BookmarkServiceInternalDefault implements BookmarkService, Serializ
     public Bookmark bookmarkFor(Class<?> cls, String identifier) {
         val spec = specificationLoader.loadSpecification(cls);
         val objectType = spec.getSpecId().asString();
-        return new Bookmark(objectType, identifier);
+        return Bookmark.of(objectType, identifier);
     }
 
     //FIXME[2112] why would we ever store Service Beans as Bookmarks?
diff --git a/extensions/vw/pdfjs/applib/src/main/java/org/apache/isis/extensions/viewer/wicket/pdfjs/applib/spi/PdfJsViewerAdvisor.java b/extensions/vw/pdfjs/applib/src/main/java/org/apache/isis/extensions/viewer/wicket/pdfjs/applib/spi/PdfJsViewerAdvisor.java
index 823756f..5570f83 100644
--- a/extensions/vw/pdfjs/applib/src/main/java/org/apache/isis/extensions/viewer/wicket/pdfjs/applib/spi/PdfJsViewerAdvisor.java
+++ b/extensions/vw/pdfjs/applib/src/main/java/org/apache/isis/extensions/viewer/wicket/pdfjs/applib/spi/PdfJsViewerAdvisor.java
@@ -2,11 +2,10 @@ package org.apache.isis.extensions.viewer.wicket.pdfjs.applib.spi;
 
 import java.io.Serializable;
 
-import org.apache.isis.extensions.viewer.wicket.pdfjs.applib.config.Scale;
-
 import org.apache.isis.applib.annotation.Programmatic;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.value.Blob;
+import org.apache.isis.extensions.viewer.wicket.pdfjs.applib.config.Scale;
 
 /**
  * SPI service interface.
@@ -31,6 +30,8 @@ public interface PdfJsViewerAdvisor {
      */
     class InstanceKey implements Serializable {
 
+        private static final long serialVersionUID = 1L;
+        
         private final TypeKey typeKey;
         private final String identifier;
 
@@ -63,7 +64,7 @@ public interface PdfJsViewerAdvisor {
 
         @Programmatic
         public Bookmark asBookmark() {
-            return new Bookmark(typeKey.objectType, identifier);
+            return Bookmark.of(typeKey.objectType, identifier);
         }
 
         @Override
@@ -104,6 +105,8 @@ public interface PdfJsViewerAdvisor {
          */
         public static class TypeKey implements Serializable {
 
+            private static final long serialVersionUID = 1L;
+            
             private final String objectType;
             private final String propertyId;
             private final String userName;
@@ -184,6 +187,8 @@ public interface PdfJsViewerAdvisor {
      */
     class Advice implements Serializable {
 
+        private static final long serialVersionUID = 1L;
+        
         private final Integer pageNum;
         private final TypeAdvice typeAdvice;
 
@@ -247,6 +252,8 @@ public interface PdfJsViewerAdvisor {
          */
         public static class TypeAdvice implements Serializable {
 
+            private static final long serialVersionUID = 1L;
+            
             private final Scale scale;
             private final Integer height;
 
diff --git a/subdomains/excel/applib/src/main/java/org/apache/isis/subdomains/excel/applib/dom/util/CellMarshaller.java b/subdomains/excel/applib/src/main/java/org/apache/isis/subdomains/excel/applib/dom/util/CellMarshaller.java
index 469de1e..48a53ca 100644
--- a/subdomains/excel/applib/src/main/java/org/apache/isis/subdomains/excel/applib/dom/util/CellMarshaller.java
+++ b/subdomains/excel/applib/src/main/java/org/apache/isis/subdomains/excel/applib/dom/util/CellMarshaller.java
@@ -475,7 +475,7 @@ final class CellMarshaller {
             return null;
         }
         final String bookmarkStr = commentRts.getString();
-        final Bookmark bookmark = new Bookmark(bookmarkStr);
+        final Bookmark bookmark = Bookmark.parse(bookmarkStr).orElse(null);
         return bookmarkService.lookup(bookmark, requiredType);
     }
     
diff --git a/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/fixturescripts/FixtureResult.java b/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/fixturescripts/FixtureResult.java
index 5a696d0..a91d4c7 100644
--- a/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/fixturescripts/FixtureResult.java
+++ b/testing/fixtures/applib/src/main/java/org/apache/isis/testing/fixtures/applib/fixturescripts/FixtureResult.java
@@ -75,7 +75,7 @@ public class FixtureResult {
     @PropertyLayout(named="Result")
     @Title(sequence="2")
     public Object getObject() {
-        return bookmarkService.lookup(new Bookmark(objectBookmark));
+        return bookmarkService.lookup(Bookmark.parse(objectBookmark).orElse(null));
     }
 
     public void setObject(Object object) {
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
index becba3e..f61b6fb 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/panels/FormExecutorDefault.java
@@ -35,14 +35,12 @@ import org.apache.wicket.util.visit.IVisit;
 import org.apache.wicket.util.visit.IVisitor;
 
 import org.apache.isis.applib.RecoverableException;
-import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.command.CommandContext;
 import org.apache.isis.applib.services.exceprecog.ExceptionRecognizer;
 import org.apache.isis.applib.services.exceprecog.ExceptionRecognizer.Category;
 import org.apache.isis.applib.services.exceprecog.ExceptionRecognizer.Recognition;
 import org.apache.isis.applib.services.exceprecog.ExceptionRecognizerService;
-import org.apache.isis.applib.services.hint.HintStore;
 import org.apache.isis.applib.services.i18n.TranslationService;
 import org.apache.isis.applib.services.message.MessageService;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
@@ -301,26 +299,10 @@ implements FormExecutor {
             final ObjectMemento targetOam,
             final ObjectMemento resultOam) {
 
-        final Bookmark resultBookmark = resultOam != null ? resultOam.asHintingBookmarkIfSupported() : null;
-        final Bookmark targetBookmark = targetOam != null ? targetOam.asHintingBookmarkIfSupported() : null;
+        val resultBookmark = resultOam != null ? resultOam.asHintingBookmarkIfSupported() : null;
+        val targetBookmark = targetOam != null ? targetOam.asHintingBookmarkIfSupported() : null;
 
-        return differs(targetBookmark, resultBookmark);
-    }
-
-    private static boolean differs(
-            final Bookmark targetBookmark,
-            final Bookmark resultBookmark) {
-
-        if(resultBookmark == null && targetBookmark == null) {
-            return true;
-        }
-        if (resultBookmark == null || targetBookmark == null) {
-            return true;
-        }
-        final String resultBookmarkStr = asStr(resultBookmark);
-        final String targetBookmarkStr = asStr(targetBookmark);
-
-        return !Objects.equals(resultBookmarkStr, targetBookmarkStr);
+        return !Objects.equals(resultBookmark, targetBookmark);
     }
 
     private boolean hasBlobsOrClobs(final Page page) {
@@ -346,12 +328,6 @@ implements FormExecutor {
         return hasBlobsOrClobs != null;
     }
 
-    private static String asStr(final Bookmark bookmark) {
-        return bookmark instanceof HintStore.BookmarkWithHintId
-                ? ((HintStore.BookmarkWithHintId) bookmark).toStringUsingHintId()
-                        : bookmark.toString();
-    }
-
 //    private void forwardOnConcurrencyException(
 //            final ManagedObject targetAdapter) {
 //
diff --git a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/HintStoreUsingWicketSession.java b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/HintStoreUsingWicketSession.java
index ed62ec9..68765a3 100644
--- a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/HintStoreUsingWicketSession.java
+++ b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/HintStoreUsingWicketSession.java
@@ -20,6 +20,7 @@ package org.apache.isis.viewer.wicket.viewer.services;
 
 import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
 
 import javax.inject.Named;
@@ -34,6 +35,7 @@ import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.hint.HintStore;
 import org.apache.isis.core.commons.internal.collections._Maps;
 
+import lombok.val;
 import lombok.extern.log4j.Log4j2;
 
 @Service
@@ -102,11 +104,11 @@ public class HintStoreUsingWicketSession implements HintStore {
     }
 
     protected String sessionAttributeFor(final Bookmark bookmark) {
-        return "hint-" + (
-                bookmark instanceof BookmarkWithHintId
-                ? ((BookmarkWithHintId) bookmark).toStringUsingHintId()
-                        : bookmark.toString()
-                );
+        
+        val id = Optional.ofNullable(bookmark.getHintId())
+                    .orElse(bookmark.getIdentifier());
+        
+        return "hint-" + bookmark.toStringUsingIdentifier(id);
     }
 
 }
diff --git a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/mementos/ObjectMementoLegacy.java b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/mementos/ObjectMementoLegacy.java
index 4221748..1b0f797 100644
--- a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/mementos/ObjectMementoLegacy.java
+++ b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/mementos/ObjectMementoLegacy.java
@@ -415,7 +415,7 @@ final class ObjectMementoLegacy implements Serializable {
     Bookmark asHintingBookmark() {
         val bookmark = asBookmark();
         return hintId != null && bookmark != null
-                ? new HintStore.BookmarkWithHintId(bookmark, hintId)
+                ? bookmark.withHintId(hintId)
                         : bookmark;
     }