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/06/03 10:24:49 UTC

[isis] branch master updated (66b10b7 -> 4430b67)

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

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


    from 66b10b7  ISIS-2371: add inline editing demo to show the issue (EventDemo)
     new 0132cb0  ISIS-2371: refactor MangedObject utilities in preparation of a fix
     new 4430b67  ISIS-2371: proposed fix

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 ...ctionInvocationFacetForDomainEventAbstract.java |   5 +-
 .../actions/action/invocation/CommandUtil.java     |   3 +-
 .../BooleanValueSemanticsProviderAbstract.java     |   3 +-
 .../metamodel/interactions/InteractionHead.java    |   5 +-
 .../interactions/managed/ManagedMember.java        |   9 +-
 .../interactions/managed/ManagedProperty.java      |   1 -
 .../objectmanager/refresh/ObjectRefresher.java     |   1 -
 .../isis/core/metamodel/spec/ManagedObject.java    | 198 ++-------------------
 .../metamodel/spec/ManagedObjectInternalUtil.java  | 101 ++++++++++-
 .../isis/core/metamodel/spec/ManagedObjects.java   | 135 +++++++++++++-
 .../core/metamodel/util/snapshot/XmlSnapshot.java  |  10 +-
 .../transaction/AdapterAndProperty.java            |   3 +-
 .../bookmarks/BookmarkServiceDefault.java          |   4 +-
 .../command/CommandDtoServiceInternalDefault.java  |   3 +-
 .../publish/PublishedObjectsDefault.java           |   3 +-
 .../DelegatingInvocationHandlerDefault.java        |   3 +-
 .../ui/component/EventProviderAbstract.java        |   3 +-
 .../persistence/IsisPersistenceSessionJdoBase.java |   3 +-
 .../common/model/binding/UiComponentFactory.java   |   3 +-
 .../AbstractObjectMemberReprRenderer.java          |   3 +-
 .../domainobjects/DomainObjectLinkTo.java          |   3 +-
 .../domainobjects/DomainObjectReprRenderer.java    |  19 +-
 .../domainobjects/ObjectActionReprRenderer.java    |   4 +-
 .../ObjectCollectionReprRenderer.java              |   3 +-
 .../viewer/context/ResourceContext.java            |   3 +-
 .../viewer/wicket/model/models/ActionModel.java    |   5 +-
 .../wicket/model/models/BookmarkTreeNode.java      |   4 +-
 .../wicket/model/models/ManagedObjectModel.java    |   5 +-
 .../wicket/model/models/PageParameterUtil.java     |   9 +-
 .../wicket/model/models/ScalarPropertyModel.java   |   2 +-
 .../entityactions/EntityActionLinkFactory.java     |   4 +-
 .../columns/ObjectAdapterTitleColumn.java          |   3 +-
 .../components/scalars/ScalarPanelAbstract2.java   |   4 +-
 .../components/tree/IsisToWicketTreeAdapter.java   |   3 +-
 .../ui/components/unknown/UnknownModelPanel.java   |   4 +-
 .../isis/viewer/wicket/ui/pages/home/HomePage.java |   4 +-
 .../integration/ConverterForObjectAdapter.java     |   5 +-
 .../ConverterForObjectAdapterMemento.java          |   4 +-
 .../services/mementos/ObjectMementoLegacy.java     |   7 +-
 .../mementos/ObjectMementoServiceWicket.java       |   3 +-
 40 files changed, 339 insertions(+), 258 deletions(-)


[isis] 01/02: ISIS-2371: refactor MangedObject utilities in preparation of a fix

Posted by ah...@apache.org.
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

commit 0132cb0867e5a9b8c2793b332114ae5693c45637
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Jun 3 12:24:18 2020 +0200

    ISIS-2371: refactor MangedObject utilities in preparation of a fix
---
 ...ctionInvocationFacetForDomainEventAbstract.java |   5 +-
 .../actions/action/invocation/CommandUtil.java     |   3 +-
 .../BooleanValueSemanticsProviderAbstract.java     |   3 +-
 .../metamodel/interactions/InteractionHead.java    |   5 +-
 .../interactions/managed/ManagedProperty.java      |   1 -
 .../objectmanager/refresh/ObjectRefresher.java     |   1 -
 .../isis/core/metamodel/spec/ManagedObject.java    | 198 ++-------------------
 .../metamodel/spec/ManagedObjectInternalUtil.java  | 101 ++++++++++-
 .../isis/core/metamodel/spec/ManagedObjects.java   | 135 +++++++++++++-
 .../core/metamodel/util/snapshot/XmlSnapshot.java  |  10 +-
 .../transaction/AdapterAndProperty.java            |   3 +-
 .../bookmarks/BookmarkServiceDefault.java          |   4 +-
 .../command/CommandDtoServiceInternalDefault.java  |   3 +-
 .../publish/PublishedObjectsDefault.java           |   3 +-
 .../DelegatingInvocationHandlerDefault.java        |   3 +-
 .../ui/component/EventProviderAbstract.java        |   3 +-
 .../persistence/IsisPersistenceSessionJdoBase.java |   3 +-
 .../common/model/binding/UiComponentFactory.java   |   3 +-
 .../AbstractObjectMemberReprRenderer.java          |   3 +-
 .../domainobjects/DomainObjectLinkTo.java          |   3 +-
 .../domainobjects/DomainObjectReprRenderer.java    |  19 +-
 .../domainobjects/ObjectActionReprRenderer.java    |   4 +-
 .../ObjectCollectionReprRenderer.java              |   3 +-
 .../viewer/context/ResourceContext.java            |   3 +-
 .../viewer/wicket/model/models/ActionModel.java    |   5 +-
 .../wicket/model/models/BookmarkTreeNode.java      |   4 +-
 .../wicket/model/models/ManagedObjectModel.java    |   5 +-
 .../wicket/model/models/PageParameterUtil.java     |   9 +-
 .../wicket/model/models/ScalarPropertyModel.java   |   2 +-
 .../entityactions/EntityActionLinkFactory.java     |   4 +-
 .../columns/ObjectAdapterTitleColumn.java          |   3 +-
 .../components/scalars/ScalarPanelAbstract2.java   |   4 +-
 .../components/tree/IsisToWicketTreeAdapter.java   |   3 +-
 .../ui/components/unknown/UnknownModelPanel.java   |   4 +-
 .../isis/viewer/wicket/ui/pages/home/HomePage.java |   4 +-
 .../integration/ConverterForObjectAdapter.java     |   5 +-
 .../ConverterForObjectAdapterMemento.java          |   4 +-
 .../services/mementos/ObjectMementoLegacy.java     |   7 +-
 .../mementos/ObjectMementoServiceWicket.java       |   3 +-
 39 files changed, 333 insertions(+), 255 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java
index c11f987..1caf339 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/ActionInvocationFacetForDomainEventAbstract.java
@@ -65,6 +65,7 @@ import org.apache.isis.core.metamodel.interactions.InteractionHead;
 import org.apache.isis.core.metamodel.services.ixn.InteractionDtoServiceInternal;
 import org.apache.isis.core.metamodel.services.publishing.PublisherDispatchService;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.schema.ixn.v2.ActionInvocationDto;
@@ -313,7 +314,7 @@ implements ImperativeFacet {
             // don't trample over any existing result, eg subsequent mixins.
             return;
         }
-        if(ManagedObject.isNullOrUnspecifiedOrEmpty(resultAdapter)) {
+        if(ManagedObjects.isNullOrUnspecifiedOrEmpty(resultAdapter)) {
             return;
         }
 
@@ -350,7 +351,7 @@ implements ImperativeFacet {
             final ManagedObject resultAdapter,
             final InteractionInitiatedBy interactionInitiatedBy) {
 
-        if(ManagedObject.isNullOrUnspecifiedOrEmpty(resultAdapter)) { 
+        if(ManagedObjects.isNullOrUnspecifiedOrEmpty(resultAdapter)) { 
             return null;
         }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/CommandUtil.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/CommandUtil.java
index 1815530..00509f0 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/CommandUtil.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/actions/action/invocation/CommandUtil.java
@@ -27,6 +27,7 @@ import org.apache.isis.core.commons.internal.collections._Arrays;
 import org.apache.isis.core.metamodel.commons.StringExtensions;
 import org.apache.isis.core.metamodel.objectmanager.ObjectManager;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
@@ -84,7 +85,7 @@ public class CommandUtil {
     }
 
     public static Bookmark bookmarkFor(final ManagedObject adapter) {
-        return ManagedObject.bookmark(adapter)
+        return ManagedObjects.bookmark(adapter)
                 .orElse(null);
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/booleans/BooleanValueSemanticsProviderAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/booleans/BooleanValueSemanticsProviderAbstract.java
index 61b8ac6..6326796 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/booleans/BooleanValueSemanticsProviderAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/value/booleans/BooleanValueSemanticsProviderAbstract.java
@@ -25,6 +25,7 @@ import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.object.parseable.TextEntryParseException;
 import org.apache.isis.core.metamodel.facets.object.value.vsp.ValueSemanticsProviderAndFacetAbstract;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 
 
 public abstract class BooleanValueSemanticsProviderAbstract
@@ -111,7 +112,7 @@ extends ValueSemanticsProviderAndFacetAbstract<Boolean> implements BooleanValueF
 
     @Override
     public boolean isSet(ManagedObject adapter) {
-        if (ManagedObject.isNullOrUnspecifiedOrEmpty(adapter)) {
+        if (ManagedObjects.isNullOrUnspecifiedOrEmpty(adapter)) {
             return false;
         }
         final Object object = adapter.getPojo();
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/InteractionHead.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/InteractionHead.java
index 73c30b0..43ac726 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/InteractionHead.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/InteractionHead.java
@@ -25,6 +25,7 @@ import javax.annotation.Nullable;
 
 import org.apache.isis.core.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 
 import lombok.AccessLevel;
 import lombok.Getter;
@@ -51,11 +52,11 @@ public class InteractionHead {
     
     /** factory with consistency checks */
     public static InteractionHead of(@NonNull ManagedObject owner, @NonNull ManagedObject target) {
-        if(ManagedObject.isSpecified(owner) 
+        if(ManagedObjects.isSpecified(owner) 
                 && owner.getSpecification().getBeanSort().isMixin()) {
             throw _Exceptions.unrecoverableFormatted("unexpected: owner is a mixin %s", owner);
         }
-        if(ManagedObject.isSpecified(target)                    
+        if(ManagedObjects.isSpecified(target)                    
                 && target.getSpecification().getBeanSort().isMixin()
                 && target.getPojo()==null) {
             throw _Exceptions.unrecoverableFormatted("target not spec. %s", target);
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedProperty.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedProperty.java
index c94507c..046c4d0 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedProperty.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedProperty.java
@@ -59,7 +59,6 @@ public final class ManagedProperty extends ManagedMember {
     private ManagedProperty(
             final @NonNull ManagedObject owner, 
             final @NonNull OneToOneAssociation property) {
-        
         super(owner);
         this.property = property;
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/refresh/ObjectRefresher.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/refresh/ObjectRefresher.java
index dcbf1ec..4b83616 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/refresh/ObjectRefresher.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/objectmanager/refresh/ObjectRefresher.java
@@ -20,7 +20,6 @@ package org.apache.isis.core.metamodel.objectmanager.refresh;
 
 import org.apache.isis.core.commons.handler.ChainOfResponsibility;
 import org.apache.isis.core.commons.internal.collections._Lists;
-import org.apache.isis.core.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 
 import lombok.val;
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObject.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObject.java
index 898aa99..aa7b61c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObject.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObject.java
@@ -35,7 +35,6 @@ import javax.annotation.Nullable;
 
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.applib.domain.DomainObjectList;
-import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.services.repository.EntityState;
 import org.apache.isis.core.commons.collections.Can;
 import org.apache.isis.core.commons.internal.base._Lazy;
@@ -53,6 +52,7 @@ import org.apache.isis.core.metamodel.facets.object.entity.EntityFacet;
 import org.apache.isis.core.metamodel.interactions.InteractionUtils;
 import org.apache.isis.core.metamodel.interactions.ObjectVisibilityContext;
 import org.apache.isis.core.metamodel.interactions.VisibilityContext;
+import org.apache.isis.core.metamodel.objectmanager.ObjectManager;
 import org.apache.isis.core.metamodel.objectmanager.create.ObjectCreator;
 import org.apache.isis.core.metamodel.objectmanager.load.ObjectLoader;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
@@ -92,64 +92,11 @@ public interface ManagedObject {
      */
     Optional<RootOid> getRootOid();
     
-    // -- SHORTCUTS
-    
-    static Optional<RootOid> identify(@Nullable ManagedObject adapter) {
-        return isSpecified(adapter)  ? adapter.getRootOid() : Optional.empty(); 
-    }
-    
-    static RootOid identifyElseFail(@Nullable ManagedObject adapter) {
-        return identify(adapter)
-                .orElseThrow(()->_Exceptions.illegalArgument("cannot identify %s", adapter));
-    }
-    
-    static Optional<Bookmark> bookmark(@Nullable ManagedObject adapter) {
-        return identify(adapter)
-                .map(RootOid::asBookmark);
-    }
-    
-    static Bookmark bookmarkElseFail(@Nullable ManagedObject adapter) {
-        return bookmark(adapter)
-                .orElseThrow(()->_Exceptions.illegalArgument("cannot bookmark %s", adapter));
-    }
-    
-    static Optional<String> stringify(@Nullable ManagedObject adapter) {
-        return identify(adapter)
-                .map(RootOid::enString);
-    }
-    
-    static String stringifyElseFail(@Nullable ManagedObject adapter) {
-        return stringify(adapter)
-                .orElseThrow(()->_Exceptions.illegalArgument("cannot stringify %s", adapter));
-    }
-    
-    
     // -- EMPTY
     
-    static class UnspecifiedHolder {
-        private static final ManagedObject UNSPECIFIED = new ManagedObject() {
-
-            @Override
-            public ObjectSpecification getSpecification() {
-                throw _Exceptions.unsupportedOperation();
-            }
-
-            @Override
-            public Object getPojo() {
-                return null;
-            }
-
-            @Override
-            public Optional<RootOid> getRootOid() {
-                return Optional.empty();
-            }
-            
-        };
-    }
-    
     /** has no ObjectSpecification and no value */
     static ManagedObject unspecified() {
-        return UnspecifiedHolder.UNSPECIFIED;
+        return ManagedObjectInternalUtil.UNSPECIFIED;
     }
     
     /** has an ObjectSpecification, but no value */
@@ -158,8 +105,6 @@ public interface ManagedObject {
     }
     
 
-    
-
     // -- SIMPLE
 
     @Value 
@@ -185,10 +130,8 @@ public interface ManagedObject {
         }
         
         // -- LAZY ID HANDLING
-        private final _Lazy<Optional<RootOid>> rootOidLazy = _Lazy.threadSafe(this::identify);  
-        private Optional<RootOid> identify() {
-            return Optional.ofNullable(ManagedObjectInternalUtil._identify(this));
-        }
+        private final _Lazy<Optional<RootOid>> rootOidLazy = 
+                _Lazy.threadSafe(()->ManagedObjectInternalUtil.identify(this));  
 
         
     }
@@ -203,7 +146,7 @@ public interface ManagedObject {
         @Getter @NonNull private final Object pojo;
         
         @Getter(lazy=true, onMethod = @__(@Override)) 
-        private final Optional<RootOid> rootOid = Optional.ofNullable(ManagedObjectInternalUtil._identify(this));
+        private final Optional<RootOid> rootOid = ManagedObjectInternalUtil.identify(this);
 
         private final _Lazy<ObjectSpecification> specification = _Lazy.threadSafe(this::loadSpec);
 
@@ -242,72 +185,16 @@ public interface ManagedObject {
     }
 
     default String titleString(@Nullable ManagedObject contextAdapterIfAny) {
-        return TitleUtil.titleString(this, contextAdapterIfAny);
+        return ManagedObjectInternalUtil.titleString(this, contextAdapterIfAny);
     }
     
-    @Deprecated // move to ManagedObjects
-    @NoArgsConstructor(access = AccessLevel.PRIVATE)
-    static final class TitleUtil {
-
-        private static String titleString(@Nullable ManagedObject managedObject, @Nullable ManagedObject contextAdapterIfAny) {
-            
-            if(!ManagedObject.isSpecified(managedObject)) {
-                return "unspecified object";
-            }
-            
-            if (managedObject.getSpecification().isParentedOrFreeCollection()) {
-                final CollectionFacet facet = managedObject.getSpecification().getFacet(CollectionFacet.class);
-                return collectionTitleString(managedObject, facet);
-            } else {
-                return objectTitleString(managedObject, contextAdapterIfAny);
-            }
-        }
-
-        private static String objectTitleString(ManagedObject managedObject, ManagedObject contextAdapterIfAny) {
-            if (managedObject.getPojo() instanceof String) {
-                return (String) managedObject.getPojo();
-            }
-            final ObjectSpecification specification = managedObject.getSpecification();
-            String title = specification.getTitle(contextAdapterIfAny, managedObject);
-
-            if (title == null) {
-                title = getDefaultTitle(managedObject);
-            }
-            return title;
-        }
-
-        private static String collectionTitleString(ManagedObject managedObject, final CollectionFacet facet) {
-            final int size = facet.size(managedObject);
-            final ObjectSpecification elementSpecification = managedObject.getElementSpecification().orElse(null);
-            if (elementSpecification == null || elementSpecification.getFullIdentifier().equals(Object.class.getName())) {
-                switch (size) {
-                case -1:
-                    return "Objects";
-                case 0:
-                    return "No objects";
-                case 1:
-                    return "1 object";
-                default:
-                    return size + " objects";
-                }
-            } else {
-                switch (size) {
-                case -1:
-                    return elementSpecification.getPluralName();
-                case 0:
-                    return "No " + elementSpecification.getPluralName();
-                case 1:
-                    return "1 " + elementSpecification.getSingularName();
-                default:
-                    return size + " " + elementSpecification.getPluralName();
-                }
-            }
-        }
-
-        private static String getDefaultTitle(ManagedObject managedObject) {
-            return "A" + (" " + managedObject.getSpecification().getSingularName()).toLowerCase();
-        }
-
+    // -- SHORTCUT - OBJECT MANAGER
+    
+    default ObjectManager getObjectManager() {
+        return ManagedObjectInternalUtil.objectManager(this)
+                .orElseThrow(()->_Exceptions
+                        .illegalArgument("Can only retrieve ObjectManager from ManagedObjects "
+                                + "that are 'specified'."));
     }
 
     // -- SHORTCUT - ELEMENT SPECIFICATION
@@ -380,7 +267,7 @@ public interface ManagedObject {
 
     @Nullable
     public static Object unwrapSingle(@Nullable final ManagedObject adapter) {
-        return isSpecified(adapter)
+        return ManagedObjects.isSpecified(adapter)
                 ? adapter.getPojo() 
                 : null;
     }
@@ -458,56 +345,7 @@ public interface ManagedObject {
                 .collect(_Sets.toUnmodifiable());
     }
 
-    // -- SHORTCUTS
-
-    public static String getDomainType(ManagedObject adapter) {
-        if(!isSpecified(adapter)) {
-            return null;
-        }
-        return adapter.getSpecification().getSpecId().asString();
-    }
-
-    // -- BASIC PREDICATES
-
-    static boolean isEntity(ManagedObject adapter) {
-        if(!isSpecified(adapter)) {
-            return false;
-        }
-        return adapter.getSpecification().isEntity();
-    }
 
-    static boolean isValue(ManagedObject adapter) {
-        if(!isSpecified(adapter)) {
-            return false;
-        }
-        return adapter.getSpecification().isValue();
-    }
-
-    /**
-     * @return whether the corresponding type can be mapped onto a REFERENCE (schema) or an Oid,
-     * that is the type is 'identifiable' (aka 'referencable' or 'bookmarkable') 
-     */
-    static boolean isIdentifiable(@Nullable ManagedObject adapter) {
-        if(!isSpecified(adapter)) {
-            return false;
-        }
-        val spec = adapter.getSpecification();
-        return spec.isIdentifiable();
-    }
-
-    static boolean isNullOrUnspecifiedOrEmpty(@Nullable ManagedObject adapter) {
-        if(adapter==null || adapter==ManagedObject.unspecified()) {
-            return true;
-        }
-        return adapter.getPojo()==null;
-    }
-    
-    /** whether has at least a spec */
-    static boolean isSpecified(@Nullable ManagedObject adapter) {
-        return adapter!=null && adapter!=ManagedObject.unspecified();
-    }
-
-    
     // -- VISIBILITY UTILITIES
 
     @Deprecated // move to ManagedObjects
@@ -570,7 +408,7 @@ public interface ManagedObject {
                 ManagedObject adapter,
                 InteractionInitiatedBy interactionInitiatedBy) {
 
-            if(isNullOrUnspecifiedOrEmpty(adapter)) {
+            if(ManagedObjects.isNullOrUnspecifiedOrEmpty(adapter)) {
                 // a choices list could include a null (eg example in ToDoItems#choices1Categorized()); want to show as "visible"
                 return true;
             }
@@ -745,7 +583,7 @@ public interface ManagedObject {
     // -- DEPRECATIONS (REFACTORING)
 
     static String _instanceId(ManagedObject adapter) {
-        val identifier = identifyElseFail(adapter).getIdentifier();
+        val identifier = ManagedObjects.identifyElseFail(adapter).getIdentifier();
         return identifier; 
     }
     
@@ -779,7 +617,7 @@ public interface ManagedObject {
             ManagedObject first,
             ManagedObject second) {
 
-        if(ManagedObject.isIdentifiable(first) && ManagedObject.isSpecified(second)) {
+        if(ManagedObjects.isIdentifiable(first) && ManagedObjects.isSpecified(second)) {
 
             val refSpec = second.getSpecification();
 
@@ -878,6 +716,8 @@ public interface ManagedObject {
         return adapter.getSpecification().getBeanSort().isCollection();
     }
 
+    
+
 
 
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObjectInternalUtil.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObjectInternalUtil.java
index a5cb1be..74dc02f 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObjectInternalUtil.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObjectInternalUtil.java
@@ -19,8 +19,15 @@
 
 package org.apache.isis.core.metamodel.spec;
 
+import java.util.Optional;
+
+import javax.annotation.Nullable;
+
+import org.apache.isis.core.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
+import org.apache.isis.core.metamodel.facets.collections.CollectionFacet;
+import org.apache.isis.core.metamodel.objectmanager.ObjectManager;
 
 import lombok.experimental.UtilityClass;
 
@@ -28,16 +35,98 @@ import lombok.experimental.UtilityClass;
  * @since 2.0
  */
 @UtilityClass
-class ManagedObjectInternalUtil {
+final class ManagedObjectInternalUtil {
+
+
+    static final ManagedObject UNSPECIFIED = new ManagedObject() {
+
+        @Override
+        public ObjectSpecification getSpecification() {
+            throw _Exceptions.unsupportedOperation();
+        }
+
+        @Override
+        public Object getPojo() {
+            return null;
+        }
+
+        @Override
+        public Optional<RootOid> getRootOid() {
+            return Optional.empty();
+        }
+        
+    };
 
-    // -- INTERNAL
+    static Optional<ObjectManager> objectManager(@Nullable ManagedObject adapter) {
+        return ManagedObjects.spec(adapter)
+        .map(ObjectSpecification::getMetaModelContext)
+        .map(MetaModelContext::getObjectManager);
+    }
+    
+    static Optional<RootOid> identify(@Nullable ManagedObject adapter) {
+        return objectManager(adapter)
+                .map(objectManager->objectManager.identifyObject(adapter)); 
+    }
+    
+    // -- TITLE SUPPORT
+    
+    static String titleString(@Nullable ManagedObject managedObject, @Nullable ManagedObject contextAdapterIfAny) {
+        
+        if(!ManagedObjects.isSpecified(managedObject)) {
+            return "unspecified object";
+        }
+        
+        if (managedObject.getSpecification().isParentedOrFreeCollection()) {
+            final CollectionFacet facet = managedObject.getSpecification().getFacet(CollectionFacet.class);
+            return collectionTitleString(managedObject, facet);
+        } else {
+            return objectTitleString(managedObject, contextAdapterIfAny);
+        }
+    }
+
+    private static String objectTitleString(ManagedObject managedObject, ManagedObject contextAdapterIfAny) {
+        if (managedObject.getPojo() instanceof String) {
+            return (String) managedObject.getPojo();
+        }
+        final ObjectSpecification specification = managedObject.getSpecification();
+        String title = specification.getTitle(contextAdapterIfAny, managedObject);
+
+        if (title == null) {
+            title = getDefaultTitle(managedObject);
+        }
+        return title;
+    }
 
-    static MetaModelContext _mmc(ManagedObject adapter) {
-        return adapter.getSpecification().getMetaModelContext();
+    private static String collectionTitleString(ManagedObject managedObject, final CollectionFacet facet) {
+        final int size = facet.size(managedObject);
+        final ObjectSpecification elementSpecification = managedObject.getElementSpecification().orElse(null);
+        if (elementSpecification == null || elementSpecification.getFullIdentifier().equals(Object.class.getName())) {
+            switch (size) {
+            case -1:
+                return "Objects";
+            case 0:
+                return "No objects";
+            case 1:
+                return "1 object";
+            default:
+                return size + " objects";
+            }
+        } else {
+            switch (size) {
+            case -1:
+                return elementSpecification.getPluralName();
+            case 0:
+                return "No " + elementSpecification.getPluralName();
+            case 1:
+                return "1 " + elementSpecification.getSingularName();
+            default:
+                return size + " " + elementSpecification.getPluralName();
+            }
+        }
     }
 
-    static RootOid _identify(ManagedObject adapter) {
-        return _mmc(adapter).getObjectManager().identifyObject(adapter); 
+    private static String getDefaultTitle(ManagedObject managedObject) {
+        return "A" + (" " + managedObject.getSpecification().getSingularName()).toLowerCase();
     }
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObjects.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObjects.java
index cc9aee7..eb82fee 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObjects.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObjects.java
@@ -20,14 +20,22 @@ package org.apache.isis.core.metamodel.spec;
 
 import java.util.Comparator;
 import java.util.Objects;
+import java.util.Optional;
 
 import javax.annotation.Nullable;
 
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.applib.services.repository.EntityState;
+import org.apache.isis.core.commons.internal.assertions._Assert;
 import org.apache.isis.core.commons.internal.base._NullSafe;
+import org.apache.isis.core.commons.internal.exceptions._Exceptions;
+import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
+import org.apache.isis.core.metamodel.objectmanager.load.ObjectLoader;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
 
+import lombok.NonNull;
 import lombok.val;
 import lombok.experimental.UtilityClass;
 
@@ -38,6 +46,84 @@ import lombok.experimental.UtilityClass;
  */
 @UtilityClass
 public final class ManagedObjects {
+    
+    // -- CATEGORISATION
+
+    public static boolean isNullOrUnspecifiedOrEmpty(@Nullable ManagedObject adapter) {
+        if(adapter==null || adapter==ManagedObject.unspecified()) {
+            return true;
+        }
+        return adapter.getPojo()==null;
+    }
+    
+    /** whether has at least a spec */
+    public static boolean isSpecified(@Nullable ManagedObject adapter) {
+        return adapter!=null && adapter!=ManagedObject.unspecified();
+    }
+    
+    /**
+     * @return whether the corresponding type can be mapped onto a REFERENCE (schema) or an Oid,
+     * that is the type is 'identifiable' (aka 'referencable' or 'bookmarkable') 
+     */
+    public static boolean isIdentifiable(@Nullable ManagedObject adapter) {
+        return spec(adapter)
+                .map(ObjectSpecification::isIdentifiable)
+                .orElse(false);
+    }
+    
+    public static boolean isEntity(ManagedObject adapter) {
+        return spec(adapter)
+                .map(ObjectSpecification::isEntity)
+                .orElse(false);
+    }
+
+    public static boolean isValue(ManagedObject adapter) {
+        return spec(adapter)
+                .map(ObjectSpecification::isValue)
+                .orElse(false);
+    }
+    
+    public static Optional<String> getDomainType(ManagedObject adapter) {
+        return spec(adapter)
+                .map(ObjectSpecification::getSpecId)
+                .map(ObjectSpecId::asString);
+    }
+    
+    // -- IDENTIFICATION
+    
+    public static Optional<ObjectSpecification> spec(@Nullable ManagedObject adapter) {
+        return isSpecified(adapter) ? Optional.of(adapter.getSpecification()) : Optional.empty(); 
+    }
+    
+    public static Optional<RootOid> identify(@Nullable ManagedObject adapter) {
+        return isSpecified(adapter) ? adapter.getRootOid() : Optional.empty(); 
+    }
+    
+    public static RootOid identifyElseFail(@Nullable ManagedObject adapter) {
+        return identify(adapter)
+                .orElseThrow(()->_Exceptions.illegalArgument("cannot identify %s", adapter));
+    }
+    
+    public static Optional<Bookmark> bookmark(@Nullable ManagedObject adapter) {
+        return identify(adapter)
+                .map(RootOid::asBookmark);
+    }
+    
+    public static Bookmark bookmarkElseFail(@Nullable ManagedObject adapter) {
+        return bookmark(adapter)
+                .orElseThrow(()->_Exceptions.illegalArgument("cannot bookmark %s", adapter));
+    }
+    
+    public static Optional<String> stringify(@Nullable ManagedObject adapter) {
+        return identify(adapter)
+                .map(RootOid::enString);
+    }
+    
+    public static String stringifyElseFail(@Nullable ManagedObject adapter) {
+        return stringify(adapter)
+                .orElseThrow(()->_Exceptions.illegalArgument("cannot stringify %s", adapter));
+    }
+
 
     // -- COMPARE UTILITIES
 
@@ -49,7 +135,7 @@ public final class ManagedObjects {
 
         final Comparator<ManagedObject> comparator = ascending 
                 ? NATURAL_NULL_FIRST 
-                        : NATURAL_NULL_FIRST.reversed();
+                : NATURAL_NULL_FIRST.reversed();
 
         return (p, q) -> {
             val pSort = sortProperty.get(p, InteractionInitiatedBy.FRAMEWORK);
@@ -121,5 +207,52 @@ public final class ManagedObjects {
         return str.length() < maxLength ? str : str.substring(0, maxLength - 3) + suffix;
     }
 
+    // -- ENTITY UTILITIES
+    
+    /**
+     * @param managedObject
+     * @return managedObject
+     * @throws AssertionError if managedObject is a detached entity  
+     */
+    public static ManagedObject requiresAttached(@NonNull ManagedObject managedObject) {
+        val entityState = ManagedObject._entityState(managedObject);
+        if(entityState.isPersistable()) {
+            // ensure we have an attached entity
+            _Assert.assertEquals(
+                    EntityState.PERSISTABLE_ATTACHED, 
+                    entityState,
+                    ()-> String.format("entity %s is required to be attached (not detached) at this stage", 
+                            managedObject.getSpecification().getSpecId()));
+        }
+        return managedObject;
+    }
+    
+    @Nullable
+    public static ManagedObject reattach(@Nullable ManagedObject managedObject) {
+        if(isNullOrUnspecifiedOrEmpty(managedObject)) {
+            return managedObject;
+        }
+        val entityState = ManagedObject._entityState(managedObject);
+        if(!entityState.isPersistable()) {
+            return managedObject;
+        }
+        if(!entityState.isDetached()) {
+            return managedObject;
+        }
+        
+        val objectIdentifier = identify(managedObject)
+                .map(RootOid::getIdentifier);
+                
+        if(!objectIdentifier.isPresent()) {
+            return managedObject;
+        }
+        
+        val objectLoadRequest = ObjectLoader.Request.of(
+                managedObject.getSpecification(), 
+                objectIdentifier.get());
+        
+        return managedObject.getObjectManager().loadObject(objectLoadRequest);
+    }
+
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/util/snapshot/XmlSnapshot.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/util/snapshot/XmlSnapshot.java
index 7651f49..41ad5b2 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/util/snapshot/XmlSnapshot.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/util/snapshot/XmlSnapshot.java
@@ -19,7 +19,6 @@
 
 package org.apache.isis.core.metamodel.util.snapshot;
 
-import java.io.StringWriter;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.List;
@@ -32,12 +31,6 @@ import java.util.stream.Collectors;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
 
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -57,6 +50,7 @@ import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
 import org.apache.isis.core.metamodel.facets.object.parseable.ParseableFacet;
 import org.apache.isis.core.metamodel.facets.object.value.ValueFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.Contributed;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
@@ -857,7 +851,7 @@ public class XmlSnapshot implements Snapshot {
             }
             return fakeOid;
         } else {
-            return ManagedObject.stringifyElseFail(adapter);
+            return ManagedObjects.stringifyElseFail(adapter);
         }
     }
 
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 48efe12..d015fc0 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
@@ -21,6 +21,7 @@ package org.apache.isis.core.runtime.persistence.transaction;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
 
 import lombok.EqualsAndHashCode;
@@ -51,7 +52,7 @@ public class AdapterAndProperty {
         this.property = property;
         this.propertyId = property.getId();
 
-        this.bookmark = ManagedObject.bookmarkElseFail(adapter);
+        this.bookmark = ManagedObjects.bookmarkElseFail(adapter);
         this.bookmarkStr = bookmark.toString();
         
     }
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/bookmarks/BookmarkServiceDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/bookmarks/BookmarkServiceDefault.java
index 17925aa..4bc848a 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/bookmarks/BookmarkServiceDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/bookmarks/BookmarkServiceDefault.java
@@ -43,7 +43,7 @@ import org.apache.isis.core.commons.internal.memento._Mementos.SerializingAdapte
 import org.apache.isis.core.metamodel.adapter.oid.ObjectNotFoundException;
 import org.apache.isis.core.metamodel.objectmanager.ObjectManager;
 import org.apache.isis.core.metamodel.objectmanager.load.ObjectLoader;
-import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 
@@ -138,7 +138,7 @@ public class BookmarkServiceDefault implements BookmarkService, SerializingAdapt
             return null;
         }
         val adapter = objectManager.adapt(unwrapped(domainObject)); 
-        if(!ManagedObject.isIdentifiable(adapter)){
+        if(!ManagedObjects.isIdentifiable(adapter)){
             // eg values cannot be bookmarked
             return null;
         }
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandDtoServiceInternalDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandDtoServiceInternalDefault.java
index 82def75..27384e2 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandDtoServiceInternalDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/command/CommandDtoServiceInternalDefault.java
@@ -39,6 +39,7 @@ import org.apache.isis.applib.util.schema.CommonDtoUtils;
 import org.apache.isis.core.metamodel.facets.actions.action.invocation.CommandUtil;
 import org.apache.isis.core.metamodel.services.command.CommandDtoServiceInternal;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
@@ -107,7 +108,7 @@ public class CommandDtoServiceInternalDefault implements CommandDtoServiceIntern
         dto.setTransactionId(transactionId);
 
         for (val targetAdapter : targetAdapters) {
-            final Bookmark bookmark = ManagedObject.bookmarkElseFail(targetAdapter);
+            final Bookmark bookmark = ManagedObjects.bookmarkElseFail(targetAdapter);
             final OidsDto targets = CommandDtoUtils.targetsFor(dto);
             targets.getOid().add(bookmark.toOidDto());
         }
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/publish/PublishedObjectsDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/publish/PublishedObjectsDefault.java
index 76cb8e0..cb1fd3c 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/publish/PublishedObjectsDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/publish/PublishedObjectsDefault.java
@@ -35,6 +35,7 @@ import org.apache.isis.core.commons.internal.collections._Maps;
 import org.apache.isis.core.commons.internal.collections._Multimaps.ListMultimap;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.schema.chg.v2.ChangesDto;
 import org.apache.isis.schema.chg.v2.ObjectsDto;
 import org.apache.isis.schema.common.v2.OidsDto;
@@ -189,7 +190,7 @@ public class PublishedObjectsDefault implements PublishedObjects, RepresentsInte
 
         _NullSafe.stream(adaptersByChange.get().get(kind))
         .map((final ManagedObject adapter) -> 
-            ManagedObject.identify(adapter)
+            ManagedObjects.identify(adapter)
             .map(RootOid::asOidDto)
             .orElse(null)
         )
diff --git a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/DelegatingInvocationHandlerDefault.java b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/DelegatingInvocationHandlerDefault.java
index 7ad4e7d..d75a83b 100644
--- a/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/DelegatingInvocationHandlerDefault.java
+++ b/core/runtimeservices/src/main/java/org/apache/isis/core/runtimeservices/wrapper/handlers/DelegatingInvocationHandlerDefault.java
@@ -30,6 +30,7 @@ import org.apache.isis.core.commons.internal._Constants;
 import org.apache.isis.core.metamodel.objectmanager.ObjectManager;
 import org.apache.isis.core.metamodel.objectmanager.load.ObjectLoader;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 
 import lombok.Getter;
 import lombok.Setter;
@@ -86,7 +87,7 @@ public class DelegatingInvocationHandlerDefault<T> implements DelegatingInvocati
         if(adapter==null) {
             return;
         }
-        if(!ManagedObject.isEntity(adapter)) {
+        if(!ManagedObjects.isEntity(adapter)) {
             return;
         }
         
diff --git a/extensions/vw/fullcalendar/ui/src/main/java/org/apache/isis/extensions/fullcalendar/ui/component/EventProviderAbstract.java b/extensions/vw/fullcalendar/ui/src/main/java/org/apache/isis/extensions/fullcalendar/ui/component/EventProviderAbstract.java
index 135814b..a1bfcf2 100644
--- a/extensions/vw/fullcalendar/ui/src/main/java/org/apache/isis/extensions/fullcalendar/ui/component/EventProviderAbstract.java
+++ b/extensions/vw/fullcalendar/ui/src/main/java/org/apache/isis/extensions/fullcalendar/ui/component/EventProviderAbstract.java
@@ -33,6 +33,7 @@ import org.joda.time.Interval;
 
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.core.webapp.context.IsisWebAppCommonContext;
@@ -108,7 +109,7 @@ public abstract class EventProviderAbstract implements EventProvider {
             final ObjectSpecification spec = specificationLoader.loadSpecification(dereferencedObject.getClass());
             final ManagedObject dereferencedManagedObject = ManagedObject.of(spec, dereferencedObject);
 
-            final RootOid rootOid = ManagedObject.identify(dereferencedManagedObject).orElse(null);
+            final RootOid rootOid = ManagedObjects.identify(dereferencedManagedObject).orElse(null);
             if(rootOid!=null) {
 
                 final String oidStr = rootOid.enString();
diff --git a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/persistence/IsisPersistenceSessionJdoBase.java b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/persistence/IsisPersistenceSessionJdoBase.java
index bee01ff..d7486e9 100644
--- a/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/persistence/IsisPersistenceSessionJdoBase.java
+++ b/persistence/jdo/datanucleus-5/src/main/java/org/apache/isis/persistence/jdo/datanucleus5/persistence/IsisPersistenceSessionJdoBase.java
@@ -40,6 +40,7 @@ import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.commons.ToString;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.core.runtime.persistence.transaction.ChangedObjectsService;
 import org.apache.isis.persistence.jdo.applib.fixturestate.FixturesInstalledStateHolder;
@@ -221,7 +222,7 @@ abstract class IsisPersistenceSessionJdoBase implements IsisPersistenceSessionJd
             return null;
         }
         val adapter = ManagedObject.of(getSpecificationLoader().loadSpecification(pojo.getClass()), pojo);
-        return ManagedObject.identify(adapter).orElse(null);
+        return ManagedObjects.identify(adapter).orElse(null);
     }
 
     // -- HELPERS - SERVICE LOOKUP
diff --git a/viewers/common/src/main/java/org/apache/isis/viewer/common/model/binding/UiComponentFactory.java b/viewers/common/src/main/java/org/apache/isis/viewer/common/model/binding/UiComponentFactory.java
index 52cb9ce..b2c84b6 100644
--- a/viewers/common/src/main/java/org/apache/isis/viewer/common/model/binding/UiComponentFactory.java
+++ b/viewers/common/src/main/java/org/apache/isis/viewer/common/model/binding/UiComponentFactory.java
@@ -31,6 +31,7 @@ import org.apache.isis.core.metamodel.interactions.managed.InteractionVeto;
 import org.apache.isis.core.metamodel.interactions.managed.ManagedMember;
 import org.apache.isis.core.metamodel.interactions.managed.ManagedProperty;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 
 import lombok.NonNull;
@@ -116,7 +117,7 @@ public interface UiComponentFactory<T> {
             //TODO do a type check before the cast, so we can throw a more detailed exception
             // that is, given type must be assignable from the actual pojo type 
             return Optional.ofNullable(managedProperty.getPropertyValue(where))
-                    .filter(_Predicates.not(ManagedObject::isNullOrUnspecifiedOrEmpty))
+                    .filter(_Predicates.not(ManagedObjects::isNullOrUnspecifiedOrEmpty))
                     .map(ManagedObject::getPojo)
                     .map(type::cast);
         }
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/AbstractObjectMemberReprRenderer.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/AbstractObjectMemberReprRenderer.java
index 97dd891..1dc3546 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/AbstractObjectMemberReprRenderer.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/AbstractObjectMemberReprRenderer.java
@@ -26,6 +26,7 @@ import org.apache.isis.core.metamodel.consent.Consent;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.interactions.managed.ManagedMember;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectFeature;
 import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
@@ -258,7 +259,7 @@ extends ReprRendererAbstract<R, ManagedMember> {
     }
 
     private void addDetailsLinkIfPersistent() {
-        if (!ManagedObject.isIdentifiable(objectAdapter)) {
+        if (!ManagedObjects.isIdentifiable(objectAdapter)) {
             return;
         }
         final JsonRepresentation link = linkTo.memberBuilder(Rel.DETAILS, objectMemberType, objectMember).build();
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectLinkTo.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectLinkTo.java
index 0956359..8afd363 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectLinkTo.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectLinkTo.java
@@ -19,6 +19,7 @@
 package org.apache.isis.viewer.restfulobjects.rendering.domainobjects;
 
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
@@ -58,7 +59,7 @@ public class DomainObjectLinkTo implements ObjectAdapterLinkTo {
      * hook method
      */
     protected StringBuilder linkRef(StringBuilder buf) {
-        String domainType = ManagedObject.getDomainType(objectAdapter);
+        String domainType = ManagedObjects.getDomainType(objectAdapter).orElse("?");
         String instanceId = ManagedObject._instanceId(objectAdapter);
         return buf.append("objects/").append(domainType).append("/").append(instanceId);
     }
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java
index bf46712..e7cbfd4 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/DomainObjectReprRenderer.java
@@ -31,6 +31,7 @@ import org.apache.isis.core.metamodel.interactions.managed.ManagedCollection;
 import org.apache.isis.core.metamodel.interactions.managed.ManagedProperty;
 import org.apache.isis.core.metamodel.services.ServiceUtil;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.Contributed;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
@@ -58,7 +59,7 @@ public class DomainObjectReprRenderer extends ReprRendererAbstract<DomainObjectR
             final Rel rel, 
             final ManagedObject objectAdapter) {
         
-        String domainType = ManagedObject.getDomainType(objectAdapter);
+        String domainType = ManagedObjects.getDomainType(objectAdapter).orElse("?");
         String instanceId = ManagedObject._instanceId(objectAdapter);
         final String url = "objects/" + domainType + "/" + instanceId;
         return LinkBuilder.newBuilder(resourceContext, rel.getName(), RepresentationType.DOMAIN_OBJECT, url).withTitle(objectAdapter.titleString(null));
@@ -69,7 +70,7 @@ public class DomainObjectReprRenderer extends ReprRendererAbstract<DomainObjectR
             final ManagedObject objectAdapter) {
         
         final Rel rel = Rel.OBJECT_LAYOUT;
-        String domainType = ManagedObject.getDomainType(objectAdapter);
+        String domainType = ManagedObjects.getDomainType(objectAdapter).orElse("?");
         String instanceId = ManagedObject._instanceId(objectAdapter);
         final String url = "objects/" + domainType + "/" + instanceId + "/object-layout";
         return LinkBuilder.newBuilder(resourceContext, rel.getName(), RepresentationType.OBJECT_LAYOUT, url);
@@ -80,7 +81,7 @@ public class DomainObjectReprRenderer extends ReprRendererAbstract<DomainObjectR
             final ManagedObject objectAdapter) {
         
         final Rel rel = Rel.OBJECT_ICON;
-        String domainType = ManagedObject.getDomainType(objectAdapter);
+        String domainType = ManagedObjects.getDomainType(objectAdapter).orElse("?");
         String instanceId = ManagedObject._instanceId(objectAdapter);
         final String url = "objects/" + domainType + "/" + instanceId + "/image";
         return LinkBuilder.newBuilder(resourceContext, rel.getName(), RepresentationType.OBJECT_IMAGE, url);
@@ -172,7 +173,7 @@ public class DomainObjectReprRenderer extends ReprRendererAbstract<DomainObjectR
         if (!(mode.isArgs())) {
 
             // self, extensions.oid
-            if (ManagedObject.isIdentifiable(objectAdapter)) {
+            if (ManagedObjects.isIdentifiable(objectAdapter)) {
                 if (includesSelf) {
                     addLinkToSelf();
                 }
@@ -219,7 +220,7 @@ public class DomainObjectReprRenderer extends ReprRendererAbstract<DomainObjectR
 
             // extensions
             getExtensions().mapPut("isService", isService);
-            getExtensions().mapPut("isPersistent", ManagedObject.isIdentifiable(objectAdapter));
+            getExtensions().mapPut("isPersistent", ManagedObjects.isIdentifiable(objectAdapter));
             if(isService) {
                 final ObjectSpecification objectSpec = objectAdapter.getSpecification();
                 final DomainServiceLayoutFacet layoutFacet =
@@ -282,7 +283,7 @@ public class DomainObjectReprRenderer extends ReprRendererAbstract<DomainObjectR
     }
 
     private String getDomainType() {
-        return ManagedObject.getDomainType(objectAdapter);
+        return ManagedObjects.getDomainType(objectAdapter).orElse("?");
     }
 
     private String getInstanceId() {
@@ -290,7 +291,7 @@ public class DomainObjectReprRenderer extends ReprRendererAbstract<DomainObjectR
     }
 
     private String getOidStr() {
-        return ManagedObject.stringifyElseFail(objectAdapter);
+        return ManagedObjects.stringifyElseFail(objectAdapter);
     }
 
     private DomainObjectReprRenderer withMembers(final ManagedObject objectAdapter) {
@@ -409,7 +410,7 @@ public class DomainObjectReprRenderer extends ReprRendererAbstract<DomainObjectR
     }
 
     private void addPersistLinkIfTransientAndPersistable() {
-        if (ManagedObject.isIdentifiable(objectAdapter)) {
+        if (ManagedObjects.isIdentifiable(objectAdapter)) {
             return;
         }
         final DomainObjectReprRenderer renderer =
@@ -442,7 +443,7 @@ public class DomainObjectReprRenderer extends ReprRendererAbstract<DomainObjectR
         if(mode.isEventSerialization()) {
             return;
         }
-        if (!ManagedObject.isIdentifiable(objectAdapter)) {
+        if (!ManagedObjects.isIdentifiable(objectAdapter)) {
             return;
         }
         final boolean isService = objectAdapter.getSpecification().isManagedBean();
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java
index 6aceb0e..cfb1687 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java
@@ -29,7 +29,7 @@ import org.apache.isis.core.commons.internal.collections._Lists;
 import org.apache.isis.core.commons.internal.collections._Maps;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.interactions.managed.ManagedAction;
-import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
@@ -181,7 +181,7 @@ public class ObjectActionReprRenderer extends AbstractObjectMemberReprRenderer<O
                 .emptyModel();
         
         val defaultAdapter = param.getDefault(emptyPpm);
-        if (ManagedObject.isNullOrUnspecifiedOrEmpty(defaultAdapter)) {
+        if (ManagedObjects.isNullOrUnspecifiedOrEmpty(defaultAdapter)) {
             return null;
         }
         // REVIEW: previously was using the spec of the parameter, but think instead it should be the spec of the adapter itself
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectCollectionReprRenderer.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectCollectionReprRenderer.java
index 4899258..e0c5de0 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectCollectionReprRenderer.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectCollectionReprRenderer.java
@@ -29,6 +29,7 @@ import org.apache.isis.core.metamodel.facets.collections.CollectionFacet;
 import org.apache.isis.core.metamodel.facets.collections.collection.defaultview.DefaultViewFacet;
 import org.apache.isis.core.metamodel.interactions.managed.ManagedCollection;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.Rel;
@@ -68,7 +69,7 @@ public class ObjectCollectionReprRenderer extends AbstractObjectMemberReprRender
         final LinkFollowSpecs followValue = getLinkFollowSpecs().follow("value");
         boolean eagerlyRender = resourceContext.honorUiHints() && renderEagerly() || !followValue.isTerminated();
 
-        if ((mode.isInline() && eagerlyRender) || mode.isStandalone() || mode.isMutated() || mode.isEventSerialization() || !ManagedObject.isIdentifiable(objectAdapter)) {
+        if ((mode.isInline() && eagerlyRender) || mode.isStandalone() || mode.isMutated() || mode.isEventSerialization() || !ManagedObjects.isIdentifiable(objectAdapter)) {
             addValue(followValue);
         }
         if(!mode.isEventSerialization()) {
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/context/ResourceContext.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/context/ResourceContext.java
index 809940c..db5a355 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/context/ResourceContext.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/context/ResourceContext.java
@@ -39,6 +39,7 @@ import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.context.MetaModelContext;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.runtime.context.RuntimeContextBase;
 import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation;
 import org.apache.isis.viewer.restfulobjects.applib.RepresentationType;
@@ -218,7 +219,7 @@ public class ResourceContext extends RuntimeContextBase implements IResourceCont
     private Set<Oid> rendered = _Sets.newHashSet();
     @Override
     public boolean canEagerlyRender(ManagedObject objectAdapter) {
-        final Oid oid = ManagedObject.identify(objectAdapter).orElse(null);
+        final Oid oid = ManagedObjects.identify(objectAdapter).orElse(null);
         return (oid!=null) 
                 ? rendered.add(oid)
                 : true;
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
index 7affbd5..0d2b752 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
@@ -52,6 +52,7 @@ import org.apache.isis.core.metamodel.facets.object.bookmarkpolicy.BookmarkPolic
 import org.apache.isis.core.metamodel.facets.object.promptStyle.PromptStyleFacet;
 import org.apache.isis.core.metamodel.interactions.InteractionHead;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
@@ -422,14 +423,14 @@ implements FormUiModel, FormExecutorContext, BookmarkableModel {
             val paramValue = actionArgumentModel.getValue();
             val hasChoices = actionParameter.hasChoices();
             val hasAutoComplete = actionParameter.hasAutoComplete();
-            val isEmpty = ManagedObject.isNullOrUnspecifiedOrEmpty(paramValue);
+            val isEmpty = ManagedObjects.isNullOrUnspecifiedOrEmpty(paramValue);
             // if we have choices or autoSelect, don't override any param value, already chosen by the user
             val vetoDefaultsToBeSet = !isEmpty 
                     && (hasChoices||hasAutoComplete);
             
             if(!vetoDefaultsToBeSet) {
                 val paramDefaultValue = actionParameter.getDefault(pendingArgs);
-                if (ManagedObject.isNullOrUnspecifiedOrEmpty(paramDefaultValue)) {
+                if (ManagedObjects.isNullOrUnspecifiedOrEmpty(paramDefaultValue)) {
                     clearParameterValue(actionParameter);
                 } else {
                     setParameterValue(actionParameter, paramDefaultValue);
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/BookmarkTreeNode.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/BookmarkTreeNode.java
index 6ca7473..9c24e21 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/BookmarkTreeNode.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/BookmarkTreeNode.java
@@ -31,7 +31,7 @@ import org.apache.isis.core.commons.internal.collections._Lists;
 import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
-import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.feature.Contributed;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
 import org.apache.isis.viewer.wicket.model.mementos.PageParameterNames;
@@ -208,7 +208,7 @@ public class BookmarkTreeNode implements Serializable {
             })
             .filter(_NullSafe::isPresent)
             .map(parentAdapter->{
-                final Oid parentOid = ManagedObject.identify(parentAdapter).orElse(null);
+                final Oid parentOid = ManagedObjects.identify(parentAdapter).orElse(null);
                 return parentOid;
             })
             .filter(_NullSafe::isPresent)
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ManagedObjectModel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ManagedObjectModel.java
index 293a5f9..991866b 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ManagedObjectModel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ManagedObjectModel.java
@@ -30,6 +30,7 @@ import org.apache.isis.core.commons.internal.collections._Collections;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facets.object.bookmarkpolicy.BookmarkPolicyFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.webapp.context.IsisWebAppCommonContext;
@@ -75,7 +76,7 @@ extends ModelAbstract<ManagedObject> {
     @Override
     public void setObject(final ManagedObject adapter) {
 
-        if(ManagedObject.isNullOrUnspecifiedOrEmpty(adapter)) {
+        if(ManagedObjects.isNullOrUnspecifiedOrEmpty(adapter)) {
             super.setObject(null);
             memento = null;
             return;
@@ -92,7 +93,7 @@ extends ModelAbstract<ManagedObject> {
     
     public void setObjectCollection(final ManagedObject adapter) {
         
-        if(ManagedObject.isNullOrUnspecifiedOrEmpty(adapter)) {
+        if(ManagedObjects.isNullOrUnspecifiedOrEmpty(adapter)) {
             super.setObject(null);
             memento = null;
             return;
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/PageParameterUtil.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/PageParameterUtil.java
index e4c1ecd..b78b873 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/PageParameterUtil.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/PageParameterUtil.java
@@ -32,6 +32,7 @@ import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
 import org.apache.isis.core.metamodel.spec.ActionType;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
@@ -68,10 +69,10 @@ public class PageParameterUtil {
     public static PageParameters createPageParametersForObject(ManagedObject adapter) {
 
         val pageParameters = PageParametersUtils.newPageParameters();
-        val isEntity = ManagedObject.isIdentifiable(adapter);
+        val isEntity = ManagedObjects.isIdentifiable(adapter);
 
         if (isEntity) {
-            ManagedObject.stringify(adapter)
+            ManagedObjects.stringify(adapter)
             .ifPresent(oidStr->PageParameterNames.OBJECT_OID.addStringTo(pageParameters, oidStr));
         } else {
             // don't do anything; instead the page should be redirected back to
@@ -103,7 +104,7 @@ public class PageParameterUtil {
 
         val pageParameters = PageParametersUtils.newPageParameters();
 
-        ManagedObject.stringify(adapter)
+        ManagedObjects.stringify(adapter)
         .ifPresent(oidStr->
             PageParameterNames.OBJECT_OID.addStringTo(pageParameters, oidStr));
 
@@ -207,7 +208,7 @@ public class PageParameterUtil {
             return encodeable.toEncodedString(adapter);
         }
 
-        return ManagedObject.stringify(adapter).orElse(null);
+        return ManagedObjects.stringify(adapter).orElse(null);
     }
     
     private ManagedObject decodeArg(
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarPropertyModel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarPropertyModel.java
index f38db89..17aba4b 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarPropertyModel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarPropertyModel.java
@@ -129,7 +129,7 @@ implements PropertyUiModel {
         val where = this.getRenderingHint().asWhere();
         val propertyValue = getManagedProperty().getPropertyValue(where);
         
-        val presentationValue = ManagedObject.isNullOrUnspecifiedOrEmpty(propertyValue)
+        val presentationValue = ManagedObjects.isNullOrUnspecifiedOrEmpty(propertyValue)
                 ? null
                 : propertyValue;
         
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/EntityActionLinkFactory.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/EntityActionLinkFactory.java
index 385f790..4313bef 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/EntityActionLinkFactory.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/EntityActionLinkFactory.java
@@ -19,7 +19,7 @@
 
 package org.apache.isis.viewer.wicket.ui.components.actionmenu.entityactions;
 
-import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
@@ -48,7 +48,7 @@ public final class EntityActionLinkFactory extends LinkAndLabelFactoryAbstract {
 
         val objectAdapter = this.targetEntityModel.getManagedObject();
 
-        val isIdentifiable = ManagedObject.isIdentifiable(objectAdapter);
+        val isIdentifiable = ManagedObjects.isIdentifiable(objectAdapter);
         if (!isIdentifiable) {
             throw new IllegalArgumentException(String.format(
                     "Object '%s' is not identifiable (has no identifier).", 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterTitleColumn.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterTitleColumn.java
index 8e49d15..0b6b459 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterTitleColumn.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/columns/ObjectAdapterTitleColumn.java
@@ -25,6 +25,7 @@ import org.apache.wicket.markup.repeater.Item;
 import org.apache.wicket.model.IModel;
 
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.webapp.context.IsisWebAppCommonContext;
 import org.apache.isis.core.webapp.context.memento.ObjectMemento;
 import org.apache.isis.viewer.common.model.object.ObjectUiModel.RenderingHint;
@@ -70,7 +71,7 @@ public class ObjectAdapterTitleColumn extends ColumnAbstract<ManagedObject> {
     private Component createComponent(final String id, final IModel<ManagedObject> rowModel) {
         val adapter = rowModel.getObject();
         
-        if(ManagedObject.isValue(adapter)) {
+        if(ManagedObjects.isValue(adapter)) {
             val valueModel = new ValueModel(super.getCommonContext(), adapter);
             
             val componentFactory = findComponentFactory(ComponentType.VALUE, valueModel);
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract2.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract2.java
index 8e4f140..46b5db6 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract2.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract2.java
@@ -47,7 +47,7 @@ import org.apache.isis.core.commons.internal.collections._Lists;
 import org.apache.isis.core.metamodel.facets.all.named.NamedFacet;
 import org.apache.isis.core.metamodel.facets.members.cssclass.CssClassFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.labelat.LabelAtFacet;
-import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.viewer.common.model.action.form.FormPendingParamUiModel;
@@ -170,7 +170,7 @@ implements ScalarModelSubscriber2 {
         val valueChanged = !Objects.equals(scalarModel.getObject(), paramValue); 
         
         if(valueChanged) {
-            if(ManagedObject.isNullOrUnspecifiedOrEmpty(paramValue)) {
+            if(ManagedObjects.isNullOrUnspecifiedOrEmpty(paramValue)) {
                 scalarModel.setObject(null);
             } else {
                 scalarModel.setObject(paramValue);
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java
index 4b51f6b..856fc2a 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/tree/IsisToWicketTreeAdapter.java
@@ -48,6 +48,7 @@ import org.apache.isis.core.commons.internal.collections._Lists;
 import org.apache.isis.core.commons.internal.functions._Functions;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.webapp.context.IsisWebAppCommonContext;
 import org.apache.isis.viewer.wicket.model.common.CommonContextUtils;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
@@ -401,7 +402,7 @@ class IsisToWicketTreeAdapter {
         public LoadableDetachableTreeModel(TreeModel tModel) {
             super(tModel);
             this.treePath = tModel.getTreePath();
-            this.id = ManagedObject.identifyElseFail(tModel.getObject());
+            this.id = ManagedObjects.identifyElseFail(tModel.getObject());
                     
             this.hashCode = Objects.hash(id.hashCode(), treePath.hashCode());
             this.commonContext = tModel.getCommonContext();
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/unknown/UnknownModelPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/unknown/UnknownModelPanel.java
index 09944f0..105cd04 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/unknown/UnknownModelPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/unknown/UnknownModelPanel.java
@@ -23,7 +23,7 @@ import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.Model;
 
-import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
 
@@ -59,7 +59,7 @@ public class UnknownModelPanel extends PanelAbstract<IModel<?>> {
             EntityModel entityModel = (EntityModel) model;
             val objectAdapter = entityModel.getObject();
             if(objectAdapter != null) {
-                buf.append("??? objectAdapter oid: " + ManagedObject.identify(objectAdapter).orElse(null));    
+                buf.append("??? objectAdapter oid: " + ManagedObjects.identify(objectAdapter).orElse(null));    
             } else {
                 buf.append("??? objectAdapter is NULL");
             }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/home/HomePage.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/home/HomePage.java
index 6cc61f0..a66ab45 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/home/HomePage.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/home/HomePage.java
@@ -24,7 +24,7 @@ import org.apache.wicket.request.cycle.RequestCycle;
 import org.apache.wicket.request.mapper.parameter.PageParameters;
 
 import org.apache.isis.applib.services.message.MessageService;
-import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
 import org.apache.isis.viewer.wicket.ui.components.widgets.breadcrumbs.BreadcrumbModelProvider;
 import org.apache.isis.viewer.wicket.ui.pages.PageAbstract;
@@ -59,7 +59,7 @@ public class HomePage extends PageAbstract {
 
         val homePageAdapter = super.getCommonContext().getHomePageAdapter();
 
-        if(ManagedObject.isSpecified(homePageAdapter)) {
+        if(ManagedObjects.isSpecified(homePageAdapter)) {
             val requestCycle = RequestCycle.get();
             requestCycle.setResponsePage(new EntityPage(getCommonContext(), homePageAdapter));
 
diff --git a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/ConverterForObjectAdapter.java b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/ConverterForObjectAdapter.java
index 2942643..f311abf 100644
--- a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/ConverterForObjectAdapter.java
+++ b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/ConverterForObjectAdapter.java
@@ -30,6 +30,7 @@ import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.objectmanager.ObjectManager;
 import org.apache.isis.core.metamodel.objectmanager.load.ObjectLoader;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 
 import lombok.val;
 
@@ -69,12 +70,12 @@ public class ConverterForObjectAdapter implements IConverter<ManagedObject> {
     @Override
     public String convertToString(final ManagedObject adapter, final Locale locale) {
         
-        if(!ManagedObject.isIdentifiable(adapter)) {
+        if(!ManagedObjects.isIdentifiable(adapter)) {
             // eg. values don't have an Oid
             return null;
         }
         
-        return ManagedObject.stringify(adapter)
+        return ManagedObjects.stringify(adapter)
                 .orElse(null);
     }
     
diff --git a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/ConverterForObjectAdapterMemento.java b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/ConverterForObjectAdapterMemento.java
index 435c053..0a7df37 100644
--- a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/ConverterForObjectAdapterMemento.java
+++ b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/integration/ConverterForObjectAdapterMemento.java
@@ -26,7 +26,7 @@ import org.apache.wicket.util.convert.IConverter;
 import org.apache.isis.core.commons.internal.base._Strings;
 import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
-import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.webapp.context.IsisWebAppCommonContext;
 import org.apache.isis.core.webapp.context.memento.ObjectMemento;
 
@@ -72,7 +72,7 @@ public class ConverterForObjectAdapterMemento implements IConverter<ObjectMement
         if(spec!=null && spec.isValue()) {
             return memento.toString();
         }
-        return ManagedObject.stringifyElseFail(adapter);
+        return ManagedObjects.stringifyElseFail(adapter);
     }
 
 }
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 1de452e..c1a58bb 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
@@ -34,6 +34,7 @@ import org.apache.isis.core.metamodel.adapter.oid.Oid;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
@@ -54,7 +55,7 @@ final class ObjectMementoLegacy implements Serializable {
      * Factory method
      */
     public static ObjectMementoLegacy createOrNull(ManagedObject adapter) {
-        if(ManagedObject.isNullOrUnspecifiedOrEmpty(adapter)) {
+        if(ManagedObjects.isNullOrUnspecifiedOrEmpty(adapter)) {
             return null;
         }
         return new ObjectMementoLegacy(adapter);
@@ -245,7 +246,7 @@ final class ObjectMementoLegacy implements Serializable {
                 //XXX REVIEW: this may be redundant because recreateAdapter also guarantees the version will be reset.
                 ManagedObject adapter = recreateObject(memento, specificationLoader);
 
-                memento.persistentOidStr = ManagedObject.stringifyElseFail(adapter);
+                memento.persistentOidStr = ManagedObjects.stringifyElseFail(adapter);
             }
 
             @Override
@@ -396,7 +397,7 @@ final class ObjectMementoLegacy implements Serializable {
             return;
         }
 
-        val rootOid = ManagedObject.identifyElseFail(adapter);
+        val rootOid = ManagedObjects.identifyElseFail(adapter);
         persistentOidStr = rootOid.enString();
         bookmark = rootOid.asBookmark();
         if(adapter.getPojo() instanceof HintStore.HintIdProvider) {
diff --git a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/mementos/ObjectMementoServiceWicket.java b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/mementos/ObjectMementoServiceWicket.java
index c3d9d61..dc985e1 100644
--- a/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/mementos/ObjectMementoServiceWicket.java
+++ b/viewers/wicket/viewer/src/main/java/org/apache/isis/viewer/wicket/viewer/services/mementos/ObjectMementoServiceWicket.java
@@ -37,6 +37,7 @@ import org.apache.isis.core.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.metamodel.adapter.oid.RootOid;
 import org.apache.isis.core.metamodel.objectmanager.ObjectManager;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.core.webapp.context.memento.ObjectMemento;
@@ -75,7 +76,7 @@ public class ObjectMementoServiceWicket implements ObjectMementoService {
         val mementoAdapter = ObjectMementoLegacy.createOrNull(adapter);
         if(mementoAdapter==null) {
             // sonar-ignore-on (fails to detect this as null guard) 
-            return ManagedObject.isSpecified(adapter)
+            return ManagedObjects.isSpecified(adapter)
                     ? new ObjectMementoForEmpty(adapter.getSpecification().getSpecId())
                     : null;
             // sonar-ignore-on


[isis] 02/02: ISIS-2371: proposed fix

Posted by ah...@apache.org.
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

commit 4430b67b48f38e03f605a8f174263e40f7c82de7
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Jun 3 12:24:35 2020 +0200

    ISIS-2371: proposed fix
---
 .../isis/core/metamodel/interactions/managed/ManagedMember.java  | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedMember.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedMember.java
index 9b6196c..91df6c6 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedMember.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedMember.java
@@ -27,6 +27,7 @@ import org.apache.isis.core.commons.internal.base._Casts;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.consent.Veto;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
@@ -87,8 +88,10 @@ public abstract class ManagedMember {
         public boolean isExplicit() {return !isAuto();}
     }
     
-    @Getter
-    private final ManagedObject owner;
+    @NonNull private ManagedObject owner;
+    public ManagedObject getOwner() {
+        return owner = ManagedObjects.reattach(owner);
+    }
     
     public abstract ObjectMember getMember();
     
@@ -173,6 +176,6 @@ public abstract class ManagedMember {
         return memberType.lookup(owner, memberId);
     }
 
-    
+
     
 }