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 2021/11/30 16:57:17 UTC

[isis] branch master updated: ISIS-2903: simplify ChainOfResponsibility to either return an object or throw

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 cfe9fa1  ISIS-2903: simplify ChainOfResponsibility to either return an object or throw
cfe9fa1 is described below

commit cfe9fa19209b4d3fafcc37ed5bf06d4623a1e084
Author: Andi Huber <ah...@apache.org>
AuthorDate: Tue Nov 30 17:57:09 2021 +0100

    ISIS-2903: simplify ChainOfResponsibility to either return an object or
    throw
    
    - that is, don't return an Optional<T>
    
    - (trouble shooting swallowed exceptions)
---
 .../commons/handler/ChainOfResponsibility.java     | 48 ++++++++----
 .../handlers/ChainOfResponsibilityTest.java        | 88 ++++++++++++++--------
 .../objectmanager/create/ObjectCreator.java        | 36 ++++-----
 .../objectmanager/detach/ObjectDetacher.java       | 21 +++---
 .../objectmanager/identify/ObjectBookmarker.java   | 33 +++-----
 .../metamodel/objectmanager/load/ObjectLoader.java | 31 +++-----
 .../objectmanager/memento/ObjectMemorizer.java     | 10 +--
 .../objectmanager/query/ObjectBulkLoader.java      | 22 ++----
 .../objectmanager/serialize/ObjectSerializer.java  | 35 ++++-----
 .../memento/ObjectMementoServiceDefault.java       |  4 -
 .../javafx/ui/components/UiComponentFactoryFx.java | 14 +---
 .../ui/components/UiComponentFactoryVaa.java       | 12 +--
 .../jdo/datanucleus/oid/JdoObjectIdSerializer.java | 68 ++++++++---------
 13 files changed, 204 insertions(+), 218 deletions(-)

diff --git a/commons/src/main/java/org/apache/isis/commons/handler/ChainOfResponsibility.java b/commons/src/main/java/org/apache/isis/commons/handler/ChainOfResponsibility.java
index 32a44e5..0e78dff 100644
--- a/commons/src/main/java/org/apache/isis/commons/handler/ChainOfResponsibility.java
+++ b/commons/src/main/java/org/apache/isis/commons/handler/ChainOfResponsibility.java
@@ -19,7 +19,8 @@
 package org.apache.isis.commons.handler;
 
 import java.util.List;
-import java.util.Optional;
+
+import org.apache.isis.commons.internal.exceptions._Exceptions;
 
 /**
  * Building blocks for the <em>Chain of Responsibility</em> design pattern.
@@ -40,7 +41,7 @@ public interface ChainOfResponsibility<X, R> {
      * @return response of the first handler that handled the request wrapped in an Optional,
      * or an empty Optional, if no handler handled the request
      */
-    Optional<R> handle(X request);
+    R handle(X request);
 
     /**
      * A chain of responsibility is made up of handlers, that are asked in sequence,
@@ -57,24 +58,43 @@ public interface ChainOfResponsibility<X, R> {
     }
 
     /**
-     * Creates a new ChainOfResponsibility of given {@code chainOfHandlers}
-     * @param <X>
-     * @param <R>
-     * @param chainOfHandlers
+     * Creates a {@link ChainOfResponsibility} for given {@code chainOfHandlers}
      */
     static <X, R> ChainOfResponsibility<X, R>
-    of(
-            final List<? extends ChainOfResponsibility.Handler<? super X, R>> chainOfHandlers) {
-
-        return request -> {
+    of(final List<? extends ChainOfResponsibility.Handler<? super X, R>> chainOfHandlers) {
 
-            final Optional<R> responseIfAny = chainOfHandlers.stream()
+        return new ChainOfResponsibility<X, R>(){
+            @Override
+            public R handle(final X request) {
+                return chainOfHandlers.stream()
                     .filter(h -> h.isHandling(request))
                     .findFirst()
-                    .map(h -> h.handle(request));
-            return responseIfAny;
+                    .orElseThrow(()->
+                        _Exceptions.noSuchElement("no handler found for request %s", request))
+                    .handle(request);
+            }
         };
-
     }
 
+    /**
+     * Creates a named {@link ChainOfResponsibility} for given {@code chainOfHandlers}
+     */
+    static <X, R> ChainOfResponsibility<X, R>
+    named(  final String name,
+            final List<? extends ChainOfResponsibility.Handler<? super X, R>> chainOfHandlers) {
+
+    return new ChainOfResponsibility<X, R>(){
+        @Override
+        public R handle(final X request) {
+            return chainOfHandlers.stream()
+                .filter(h -> h.isHandling(request))
+                .findFirst()
+                .orElseThrow(()->
+                    _Exceptions.noSuchElement("no %s handler found for request %s", name, request))
+                .handle(request);
+        }
+    };
+}
+
+
 }
diff --git a/commons/src/test/java/org/apache/isis/commons/handlers/ChainOfResponsibilityTest.java b/commons/src/test/java/org/apache/isis/commons/handlers/ChainOfResponsibilityTest.java
index 1b16849..2aede5a 100644
--- a/commons/src/test/java/org/apache/isis/commons/handlers/ChainOfResponsibilityTest.java
+++ b/commons/src/test/java/org/apache/isis/commons/handlers/ChainOfResponsibilityTest.java
@@ -19,13 +19,15 @@
 package org.apache.isis.commons.handlers;
 
 import java.util.Arrays;
+import java.util.NoSuchElementException;
 
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 
 import org.apache.isis.commons.handler.ChainOfResponsibility;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
 
 import lombok.val;
 
@@ -33,89 +35,109 @@ class ChainOfResponsibilityTest {
 
     @Test
     void threeHandlers_shouldProperlyTakeResponsibilityInOrder() {
-        
+
         val aToUpperCase = new ChainOfResponsibility.Handler<String, String>() {
 
             @Override
-            public boolean isHandling(String request) {
+            public boolean isHandling(final String request) {
                 return request.startsWith("a");
             }
 
             @Override
-            public String handle(String request) {
+            public String handle(final String request) {
                 return request.toUpperCase();
             }
-            
+
         };
 
         val bToUpperCase = new ChainOfResponsibility.Handler<String, String>() {
 
             @Override
-            public boolean isHandling(String request) {
+            public boolean isHandling(final String request) {
                 return request.startsWith("b");
             }
 
             @Override
-            public String handle(String request) {
+            public String handle(final String request) {
                 return request.toUpperCase();
             }
-            
+
         };
 
         val finallyNoop = new ChainOfResponsibility.Handler<String, String>() {
 
             @Override
-            public boolean isHandling(String request) {
+            public boolean isHandling(final String request) {
                 return true;
             }
 
             @Override
-            public String handle(String request) {
+            public String handle(final String request) {
                 return request;
             }
-            
+
         };
-        
+
         val chainOfResponsibility = ChainOfResponsibility.of(
-                Arrays.asList(aToUpperCase, bToUpperCase, finallyNoop)); 
-        
-        
-        assertEquals("ASTRING", chainOfResponsibility.handle("aString").orElse(null)); // handled by first handler
-        assertEquals("BSTRING", chainOfResponsibility.handle("bString").orElse(null)); // handled by second handler
-        assertEquals("cString", chainOfResponsibility.handle("cString").orElse(null)); // handled by third handler
-        
+                Arrays.asList(aToUpperCase, bToUpperCase, finallyNoop));
+
+        assertEquals("ASTRING", chainOfResponsibility.handle("aString")); // handled by first handler
+        assertEquals("BSTRING", chainOfResponsibility.handle("bString")); // handled by second handler
+        assertEquals("cString", chainOfResponsibility.handle("cString")); // handled by third handler
+
     }
-    
+
     // sample extension
     static interface StringHandler extends ChainOfResponsibility.Handler<String, String>{
-        
+
     }
-    
-    
+
     @Test
     void whenExtended_shouldWorkAsWell() {
-    
+
         val aToUpperCase = new StringHandler() {
 
             @Override
-            public boolean isHandling(String request) {
+            public boolean isHandling(final String request) {
                 return request.startsWith("a");
             }
 
             @Override
-            public String handle(String request) {
+            public String handle(final String request) {
                 return request.toUpperCase();
             }
-            
+
         };
-        
+
         val handlers = Arrays.asList(aToUpperCase);
-        
+
         val chainOfResponsibility = ChainOfResponsibility.of(handlers);
-        
-        assertEquals("ASTRING", chainOfResponsibility.handle("aString").orElse(null)); // handled by first handler
-        assertFalse(chainOfResponsibility.handle("xxx").isPresent()); // not handled
-        
+
+        assertEquals("ASTRING", chainOfResponsibility.handle("aString")); // handled by first handler
+        assertThrows(NoSuchElementException.class, ()->chainOfResponsibility.handle("xxx")); // not handled
+    }
+
+    @Test
+    void handlerExceptions_shouldNoBeSwallowed() {
+
+        val throwingHandler = new ChainOfResponsibility.Handler<String, String>() {
+
+            @Override
+            public boolean isHandling(final String request) {
+                return request.startsWith("throw");
+            }
+
+            @Override
+            public String handle(final String request) {
+                throw _Exceptions.unrecoverable("for testing purposes");
+            }
+
+        };
+
+        val chainOfResponsibility = ChainOfResponsibility.of(
+                Arrays.asList(throwingHandler));
+
+        assertThrows(RuntimeException.class, ()->chainOfResponsibility.handle("throw"));
     }
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/create/ObjectCreator.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/create/ObjectCreator.java
index a565895..c069931 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/create/ObjectCreator.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/create/ObjectCreator.java
@@ -18,17 +18,14 @@
  */
 package org.apache.isis.core.metamodel.objectmanager.create;
 
-import java.util.List;
-
 import org.apache.isis.commons.handler.ChainOfResponsibility;
-import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.core.metamodel.context.HasMetaModelContext;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 
 import lombok.Value;
-import lombok.val;
 
 /**
  * @since 2.0
@@ -57,23 +54,20 @@ public interface ObjectCreator {
 
     public static ObjectCreator createDefault(final MetaModelContext mmc) {
 
-        val chainOfHandlers = List.of(
-                new ObjectCreator_builtinHandlers.DefaultCreationHandler(mmc)
-
-//                new ObjectCreator_builtinHandlers.GuardAgainstNull(),
-//                new ObjectCreator_builtinHandlers.LoadService(),
-//                new ObjectCreator_builtinHandlers.CreateValueDefault(),
-//                new ObjectCreator_builtinHandlers.CreateViewModel(),
-//                new ObjectCreator_builtinHandlers.CreateEntity(),
-//                new ObjectCreator_builtinHandlers.CreateOther()
-                );
-
-        val chainOfRespo = ChainOfResponsibility.of(chainOfHandlers);
-
-        return request -> chainOfRespo
-                .handle(request)
-                .orElseThrow(()->_Exceptions.unrecoverableFormatted(
-                        "ObjectCreator failed to hanlde request %s", request));
+        return request ->
+        ChainOfResponsibility.named(
+                "ObjectCreator",
+                _Lists.of(
+                        new ObjectCreator_builtinHandlers.DefaultCreationHandler(mmc)
+//                      new ObjectCreator_builtinHandlers.GuardAgainstNull(),
+//                      new ObjectCreator_builtinHandlers.LoadService(),
+//                      new ObjectCreator_builtinHandlers.CreateValueDefault(),
+//                      new ObjectCreator_builtinHandlers.CreateViewModel(),
+//                      new ObjectCreator_builtinHandlers.CreateEntity(),
+//                      new ObjectCreator_builtinHandlers.CreateOther()
+                        )
+        )
+        .handle(request);
 
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/detach/ObjectDetacher.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/detach/ObjectDetacher.java
index 65be794..0045575 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/detach/ObjectDetacher.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/detach/ObjectDetacher.java
@@ -23,8 +23,6 @@ import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 
-import lombok.val;
-
 /**
  *
  * @since 2.0
@@ -43,16 +41,15 @@ public interface ObjectDetacher {
 
     // -- FACTORY
 
-    public static ObjectDetacher createDefault(MetaModelContext metaModelContext) {
-
-        val chainOfHandlers = _Lists.of(
-                new ObjectDetacher_builtinHandlers.GuardAgainstNull(),
-                new ObjectDetacher_builtinHandlers.DetachEntity(metaModelContext),
-                new ObjectDetacher_builtinHandlers.DetachOther());
-
-        val chainOfRespo = ChainOfResponsibility.of(chainOfHandlers);
-
-        return request -> chainOfRespo.handle(request).orElse(null);
+    public static ObjectDetacher createDefault(final MetaModelContext metaModelContext) {
+        return request ->
+        ChainOfResponsibility.named(
+                "ObjectDetacher",
+                _Lists.of(
+                        new ObjectDetacher_builtinHandlers.GuardAgainstNull(),
+                        new ObjectDetacher_builtinHandlers.DetachEntity(metaModelContext),
+                        new ObjectDetacher_builtinHandlers.DetachOther()))
+            .handle(request);
 
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/identify/ObjectBookmarker.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/identify/ObjectBookmarker.java
index 5cf2336..b93fa76 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/identify/ObjectBookmarker.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/identify/ObjectBookmarker.java
@@ -21,11 +21,8 @@ package org.apache.isis.core.metamodel.objectmanager.identify;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.commons.handler.ChainOfResponsibility;
 import org.apache.isis.commons.internal.collections._Lists;
-import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 
-import lombok.val;
-
 /**
  * @since 2.0
  */
@@ -40,24 +37,18 @@ public interface ObjectBookmarker {
     // -- FACTORY
 
     public static ObjectBookmarker createDefault() {
-
-        val chainOfHandlers = _Lists.of(
-                new ObjectBookmarker_builtinHandlers.GuardAgainstOid(),
-                new ObjectBookmarker_builtinHandlers.BookmarkForServices(),
-                new ObjectBookmarker_builtinHandlers.BookmarkForValues(),
-                new ObjectBookmarker_builtinHandlers.BookmarkForSerializable(),
-                new ObjectBookmarker_builtinHandlers.BookmarkForViewModels(),
-                new ObjectBookmarker_builtinHandlers.BookmarkForEntities(),
-                new ObjectBookmarker_builtinHandlers.BookmarkForOthers());
-
-        val chainOfRespo = ChainOfResponsibility.of(chainOfHandlers);
-
-        return managedObject -> chainOfRespo
-                .handle(managedObject)
-                .orElseThrow(()->_Exceptions.unrecoverableFormatted(
-                        "Could not identify ManagedObject: %s", managedObject));
-
-
+        return managedObject ->
+            ChainOfResponsibility.named(
+                    "ObjectBookmarker",
+                    _Lists.of(
+                            new ObjectBookmarker_builtinHandlers.GuardAgainstOid(),
+                            new ObjectBookmarker_builtinHandlers.BookmarkForServices(),
+                            new ObjectBookmarker_builtinHandlers.BookmarkForValues(),
+                            new ObjectBookmarker_builtinHandlers.BookmarkForSerializable(),
+                            new ObjectBookmarker_builtinHandlers.BookmarkForViewModels(),
+                            new ObjectBookmarker_builtinHandlers.BookmarkForEntities(),
+                            new ObjectBookmarker_builtinHandlers.BookmarkForOthers()))
+            .handle(managedObject);
     }
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/load/ObjectLoader.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/load/ObjectLoader.java
index 06fec31..99cdaf1 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/load/ObjectLoader.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/load/ObjectLoader.java
@@ -20,14 +20,12 @@ package org.apache.isis.core.metamodel.objectmanager.load;
 
 import org.apache.isis.commons.handler.ChainOfResponsibility;
 import org.apache.isis.commons.internal.collections._Lists;
-import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.metamodel.context.HasMetaModelContext;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 
 import lombok.Value;
-import lombok.val;
 
 /**
  * @since 2.0
@@ -56,23 +54,18 @@ public interface ObjectLoader {
     // -- FACTORY
 
     public static ObjectLoader createDefault(final MetaModelContext mmc) {
-
-        val chainOfHandlers = _Lists.of(
-                new ObjectLoader_builtinHandlers.GuardAgainstNull(mmc),
-                new ObjectLoader_builtinHandlers.LoadService(mmc),
-                new ObjectLoader_builtinHandlers.LoadValue(mmc),
-                new ObjectLoader_builtinHandlers.LoadSerializable(mmc),
-                new ObjectLoader_builtinHandlers.LoadViewModel(mmc),
-                new ObjectLoader_builtinHandlers.LoadEntity(mmc),
-                new ObjectLoader_builtinHandlers.LoadOther(mmc));
-
-        val chainOfRespo = ChainOfResponsibility.of(chainOfHandlers);
-
-        return request -> chainOfRespo
-                .handle(request)
-                .orElseThrow(()->_Exceptions.unrecoverableFormatted(
-                        "ObjectLoader failed to handle request %s", request));
-
+        return request ->
+        ChainOfResponsibility.named(
+                "ObjectLoader",
+                _Lists.of(
+                        new ObjectLoader_builtinHandlers.GuardAgainstNull(mmc),
+                        new ObjectLoader_builtinHandlers.LoadService(mmc),
+                        new ObjectLoader_builtinHandlers.LoadValue(mmc),
+                        new ObjectLoader_builtinHandlers.LoadSerializable(mmc),
+                        new ObjectLoader_builtinHandlers.LoadViewModel(mmc),
+                        new ObjectLoader_builtinHandlers.LoadEntity(mmc),
+                        new ObjectLoader_builtinHandlers.LoadOther(mmc)))
+            .handle(request);
     }
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/memento/ObjectMemorizer.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/memento/ObjectMemorizer.java
index bd53925..3b15675 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/memento/ObjectMemorizer.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/memento/ObjectMemorizer.java
@@ -37,7 +37,7 @@ public interface ObjectMemorizer {
     /**
      * Does both, serialize or deserialize, depending on the request's type.
      * @apiNote Rather use the more convenient specialized variants
-     * {@link #serialize(ManagedObject)} and {@link #deserialize(ObjectSpecification, ObjectMemento))}
+     * {@link #serialize(ManagedObject)} and {@link #deserialize(ObjectSpecification, ObjectMemento)}
      * @param request
      */
     BiForm serializeObject(BiForm request);
@@ -125,8 +125,6 @@ public interface ObjectMemorizer {
                 new ObjectMemorizer_builtinHandlers.MemorizeOther()
                 );
 
-
-
         if(metaModelContext instanceof MetaModelContext_forTesting) {
             ((MetaModelContext_forTesting)(metaModelContext))
             .registerPostconstruct(()->chainOfHandlers.forEach(serviceInjector::injectServicesInto));
@@ -134,10 +132,8 @@ public interface ObjectMemorizer {
             chainOfHandlers.forEach(serviceInjector::injectServicesInto);
         }
 
-        val chainOfRespo = ChainOfResponsibility.of(chainOfHandlers);
-
-        return request -> chainOfRespo.handle(request).orElse(null);
-
+        return request -> ChainOfResponsibility.of(chainOfHandlers)
+                .handle(request);
     }
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/query/ObjectBulkLoader.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/query/ObjectBulkLoader.java
index 92511a7..76b6c30 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/query/ObjectBulkLoader.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/query/ObjectBulkLoader.java
@@ -22,14 +22,12 @@ import org.apache.isis.applib.query.Query;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.handler.ChainOfResponsibility;
 import org.apache.isis.commons.internal.collections._Lists;
-import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.metamodel.context.HasMetaModelContext;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 
 import lombok.Value;
-import lombok.val;
 
 /**
  * @since 2.0
@@ -57,18 +55,14 @@ public interface ObjectBulkLoader {
     // -- FACTORY
 
     public static ObjectBulkLoader createDefault(final MetaModelContext mmc) {
-
-        val chainOfHandlers = _Lists.of(
-                new ObjectBulkLoader_builtinHandlers.GuardAgainstNull(mmc),
-                new ObjectBulkLoader_builtinHandlers.BulkLoadEntity(mmc),
-                new ObjectBulkLoader_builtinHandlers.LoadOther(mmc));
-
-        val chainOfRespo = ChainOfResponsibility.of(chainOfHandlers);
-
-        return request -> chainOfRespo
-                .handle(request)
-                .orElseThrow(()->_Exceptions.unrecoverableFormatted(
-                        "ObjectBulkLoader failed to handle request %s", request));
+        return request ->
+            ChainOfResponsibility.named(
+                    "ObjectBulkLoader",
+                    _Lists.of(
+                            new ObjectBulkLoader_builtinHandlers.GuardAgainstNull(mmc),
+                            new ObjectBulkLoader_builtinHandlers.BulkLoadEntity(mmc),
+                            new ObjectBulkLoader_builtinHandlers.LoadOther(mmc)))
+                .handle(request);
     }
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/serialize/ObjectSerializer.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/serialize/ObjectSerializer.java
index c672a46..d3bec53 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/serialize/ObjectSerializer.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/serialize/ObjectSerializer.java
@@ -40,13 +40,13 @@ public interface ObjectSerializer {
      */
     BiForm serializeObject(BiForm request);
 
-    default ManagedObject deserialize(ObjectSpecification spec, byte[] serializedObjectBytes) {
+    default ManagedObject deserialize(final ObjectSpecification spec, final byte[] serializedObjectBytes) {
         val request = BiForm.deSerializationRequest(SerializedObject.of(spec, serializedObjectBytes));
         val response = serializeObject(request);
         return response.getObject();
     }
 
-    default byte[] serialize(ManagedObject object) {
+    default byte[] serialize(final ManagedObject object) {
         val request = BiForm.serializationRequest(object);
         val response = serializeObject(request);
         return response.getSerializedObject().getSerializedObjectBytes();
@@ -66,16 +66,16 @@ public interface ObjectSerializer {
         @Nullable private SerializedObject serializedObject;
         public boolean isSerialized() { return serializedObject!=null; }
         public boolean isDeserialized() { return object!=null; }
-        public static BiForm serializationRequest(ManagedObject object) {
+        public static BiForm serializationRequest(final ManagedObject object) {
             return of(object, null);
         }
-        public static BiForm deSerializationRequest(SerializedObject serializedObject) {
+        public static BiForm deSerializationRequest(final SerializedObject serializedObject) {
             return of(null, serializedObject);
         }
-        public static BiForm serializationResponse(SerializedObject serializedObject) {
+        public static BiForm serializationResponse(final SerializedObject serializedObject) {
             return of(null, serializedObject);
         }
-        public static BiForm deSerializationResponse(ManagedObject object) {
+        public static BiForm deSerializationResponse(final ManagedObject object) {
             return of(object, null);
         }
         public ObjectSpecification getSpecification() {
@@ -91,13 +91,13 @@ public interface ObjectSerializer {
     extends ChainOfResponsibility.Handler<BiForm, BiForm> {
 
         @Override
-        default boolean isHandling(BiForm request) {
+        default boolean isHandling(final BiForm request) {
             val spec = request.getSpecification();
             return isHandling(spec);
         }
 
         @Override
-        default BiForm handle(BiForm request) {
+        default BiForm handle(final BiForm request) {
             val spec = request.getSpecification();
             if(request.isSerialized()) {
                 val serializedObjectBytes = request.getSerializedObject().getSerializedObjectBytes();
@@ -115,17 +115,14 @@ public interface ObjectSerializer {
 
     // -- FACTORY
 
-    public static ObjectSerializer createDefault(MetaModelContext metaModelContext) {
-
-        val chainOfHandlers = _Lists.<ObjectSerializer.Handler>of(
-                new ObjectSerializer_builtinHandlers.SerializeSerializable(),
-                new ObjectSerializer_builtinHandlers.SerializeOther()
-                );
-
-        val chainOfRespo = ChainOfResponsibility.of(chainOfHandlers);
-
-        return request -> chainOfRespo.handle(request).orElse(null);
-
+    public static ObjectSerializer createDefault(final MetaModelContext metaModelContext) {
+        return request ->
+        ChainOfResponsibility.named(
+                "ObjectSerializer",
+                _Lists.of(
+                        new ObjectSerializer_builtinHandlers.SerializeSerializable(),
+                        new ObjectSerializer_builtinHandlers.SerializeOther()))
+            .handle(request);
     }
 
 }
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/memento/ObjectMementoServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/memento/ObjectMementoServiceDefault.java
index 910c915..6d8d50e 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/memento/ObjectMementoServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/memento/ObjectMementoServiceDefault.java
@@ -210,10 +210,6 @@ public class ObjectMementoServiceDefault implements ObjectMementoService {
             return delegate.toString();
         }
 
-
-
     }
 
-
-
 }
diff --git a/incubator/viewers/javafx/ui/src/main/java/org/apache/isis/incubator/viewer/javafx/ui/components/UiComponentFactoryFx.java b/incubator/viewers/javafx/ui/src/main/java/org/apache/isis/incubator/viewer/javafx/ui/components/UiComponentFactoryFx.java
index 1a66328..434227e 100644
--- a/incubator/viewers/javafx/ui/src/main/java/org/apache/isis/incubator/viewer/javafx/ui/components/UiComponentFactoryFx.java
+++ b/incubator/viewers/javafx/ui/src/main/java/org/apache/isis/incubator/viewer/javafx/ui/components/UiComponentFactoryFx.java
@@ -27,7 +27,6 @@ import org.springframework.stereotype.Service;
 
 import org.apache.isis.applib.annotation.LabelPosition;
 import org.apache.isis.commons.handler.ChainOfResponsibility;
-import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.config.environment.IsisSystemEnvironment;
 import org.apache.isis.core.metamodel.facets.objectvalue.labelat.LabelAtFacet;
 import org.apache.isis.core.metamodel.interactions.managed.ManagedMember;
@@ -61,7 +60,7 @@ public class UiComponentFactoryFx implements UiComponentFactory<Node, Node> {
 
         this.isPrototyping = isisSystemEnvironment.isPrototyping();
         this.uiContext = uiContext;
-        this.chainOfHandlers = ChainOfResponsibility.of(handlers);
+        this.chainOfHandlers = ChainOfResponsibility.named("Component Mapper", handlers);
         this.registeredHandlers = handlers.stream()
                 .map(Handler::getClass)
                 .collect(Collectors.toList());
@@ -70,11 +69,7 @@ public class UiComponentFactoryFx implements UiComponentFactory<Node, Node> {
     @Override
     public Node componentFor(final ComponentRequest request) {
 
-        val formField = chainOfHandlers
-                .handle(request)
-                .orElseThrow(()->_Exceptions.unrecoverableFormatted(
-                        "Component Mapper failed to handle request %s", request));
-
+        val formField = chainOfHandlers.handle(request);
         val managedMember = (ManagedMember) request.getManagedFeature();
 
         request.getDisablingUiModelIfAny().ifPresent(disablingUiModel->{
@@ -111,10 +106,7 @@ public class UiComponentFactoryFx implements UiComponentFactory<Node, Node> {
 
     @Override
     public Node parameterFor(final ComponentRequest request) {
-        val formField = chainOfHandlers
-                .handle(request)
-                .orElseThrow(()->_Exceptions.unrecoverableFormatted(
-                        "Component Mapper failed to handle request %s", request));
+        val formField = chainOfHandlers.handle(request);
         return formField;
     }
 
diff --git a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/UiComponentFactoryVaa.java b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/UiComponentFactoryVaa.java
index c01b109..78cc5af 100644
--- a/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/UiComponentFactoryVaa.java
+++ b/incubator/viewers/vaadin/ui/src/main/java/org/apache/isis/incubator/viewer/vaadin/ui/components/UiComponentFactoryVaa.java
@@ -46,7 +46,7 @@ public class UiComponentFactoryVaa implements UiComponentFactory<Component, Comp
 
     @Inject
     private UiComponentFactoryVaa(final List<Handler<Component>> handlers) {
-        this.chainOfHandlers = ChainOfResponsibility.of(handlers);
+        this.chainOfHandlers = ChainOfResponsibility.named("UiComponentFactoryVaa", handlers);
         this.registeredHandlers = handlers.stream()
                 .map(Handler::getClass)
                 .collect(Collectors.toList());
@@ -77,18 +77,12 @@ public class UiComponentFactoryVaa implements UiComponentFactory<Component, Comp
 
     @Override
     public Component componentFor(final ComponentRequest request) {
-        return chainOfHandlers
-                .handle(request)
-                .orElseThrow(()->_Exceptions.unrecoverableFormatted(
-                        "Component Mapper failed to handle request %s", request));
+        return chainOfHandlers.handle(request);
     }
 
     @Override
     public Component parameterFor(final ComponentRequest request) {
-        return chainOfHandlers
-                .handle(request)
-                .orElseThrow(()->_Exceptions.unrecoverableFormatted(
-                        "Component Mapper failed to handle request %s", request));
+        return chainOfHandlers.handle(request);
     }
 
     @Override
diff --git a/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/oid/JdoObjectIdSerializer.java b/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/oid/JdoObjectIdSerializer.java
index cabe9ce..4acea86 100644
--- a/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/oid/JdoObjectIdSerializer.java
+++ b/persistence/jdo/datanucleus/src/main/java/org/apache/isis/persistence/jdo/datanucleus/oid/JdoObjectIdSerializer.java
@@ -28,7 +28,6 @@ import java.util.Optional;
 import java.util.UUID;
 import java.util.function.Function;
 
-import org.springframework.lang.Nullable;
 import javax.jdo.PersistenceManager;
 import javax.jdo.identity.ByteIdentity;
 import javax.jdo.identity.IntIdentity;
@@ -37,6 +36,7 @@ import javax.jdo.identity.ObjectIdentity;
 import javax.jdo.identity.StringIdentity;
 
 import org.datanucleus.identity.DatastoreId;
+import org.springframework.lang.Nullable;
 
 import org.apache.isis.applib.services.bookmark.Oid;
 import org.apache.isis.commons.handler.ChainOfResponsibility;
@@ -74,36 +74,12 @@ public final class JdoObjectIdSerializer {
     }
 
     public static String toOidIdentifier(final Object jdoOid) {
-
-        return encodingChain.handle(jdoOid)
-        .orElseGet(()->
-            // the JDO spec (5.4.3) requires that OIDs are serializable toString and
-            // re-create-able through the constructor
-            jdoOid.getClass().getName() + SEPARATOR + jdoOid.toString());
+        return encodingChain.handle(jdoOid);
     }
 
-    public static Object toJdoObjectId(ObjectSpecification spec, Oid oid) {
-
+    public static Object toJdoObjectId(final ObjectSpecification spec, final Oid oid) {
         val request = JdoObjectIdDecodingRequest.parse(spec, oid.getIdentifier());
-
-        return decodingChain.handle(request)
-        .orElseGet(()->{
-
-            val clsName = request.getDistinguisher();
-            val keyStr = request.getKeyStr();
-
-            try {
-                final Class<?> cls = _Context.loadClass(clsName);
-                final Constructor<?> cons = cls.getConstructor(String.class);
-                final Object dnOid = cons.newInstance(keyStr);
-                return dnOid.toString();
-            } catch (ClassNotFoundException | IllegalArgumentException | InstantiationException | IllegalAccessException | SecurityException | InvocationTargetException | NoSuchMethodException e) {
-                throw _Exceptions.unrecoverableFormatted(
-                        "failed to instantiate %s with arg %s", clsName, keyStr, e);
-            }
-
-        });
-
+        return decodingChain.handle(request);
     }
 
     // -- HELPER
@@ -173,6 +149,16 @@ public final class JdoObjectIdSerializer {
                             final DatastoreId dnOid = (DatastoreId) jdoOid;
                             // no separator
                             return "" + dnOid.getKeyAsObject();
+                        }),
+                // fallback
+                _JdoObjectIdEncoder.of(
+                        jdoOid->{
+                            return true; // last handler in the chain
+                        },
+                        jdoOid->{
+                            // the JDO spec (5.4.3) requires that OIDs are serializable toString and
+                            // re-create-able through the constructor
+                            return jdoOid.getClass().getName() + SEPARATOR + jdoOid.toString();
                         })
                 );
         return encoders;
@@ -213,19 +199,33 @@ public final class JdoObjectIdSerializer {
                         JdoObjectIdDecodingRequest::getKeyStr),
                 _JdoObjectIdDecoder.of(
                         request->dnPrefixes.contains(request.getDistinguisher()),
-                        request->request.getKeyStr() + "[OID]" + request.getSpec().getFullIdentifier())
-
+                        request->request.getKeyStr() + "[OID]" + request.getSpec().getFullIdentifier()),
+                //fallback
+                _JdoObjectIdDecoder.of(
+                        request->true, // last handler in the chain
+                        request->{
+                            val clsName = request.getDistinguisher();
+                            val keyStr = request.getKeyStr();
+
+                            try {
+                                final Class<?> cls = _Context.loadClass(clsName);
+                                final Constructor<?> cons = cls.getConstructor(String.class);
+                                final Object dnOid = cons.newInstance(keyStr);
+                                return dnOid.toString();
+                            } catch (ClassNotFoundException | IllegalArgumentException | InstantiationException | IllegalAccessException | SecurityException | InvocationTargetException | NoSuchMethodException e) {
+                                throw _Exceptions.unrecoverableFormatted(
+                                        "failed to instantiate %s with arg %s", clsName, keyStr, e);
+                            }
+                        })
                 );
         return decoders;
     }
 
     private final static ChainOfResponsibility<Object, String>
-        encodingChain = ChainOfResponsibility.of(encoders());
+        encodingChain = ChainOfResponsibility.named("JdoObjectIdEncoder", encoders());
 
     private final static ChainOfResponsibility<JdoObjectIdDecodingRequest, Object>
-        decodingChain = ChainOfResponsibility.of(decoders());
-
-
+        decodingChain = ChainOfResponsibility.named("JdoObjectIdDecoder", decoders());
 
 
 }