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 8bc96a1d81 ISIS-3167: refactor ManagedObject nested types into their 
own files
8bc96a1d81 is described below

commit 8bc96a1d812d671a930540594bae13ec1da29b8e
Author: Andi Huber <[email protected]>
AuthorDate: Sat Aug 27 15:05:09 2022 +0200

    ISIS-3167: refactor ManagedObject nested types into their own files
---
 .../isis/core/metamodel/object/ManagedObject.java  | 284 +--------------------
 .../isis/core/metamodel/object/ManagedObjects.java |  42 +--
 .../core/metamodel/object/PackedManagedObject.java |  64 +----
 .../metamodel/object/_ManagedObjectAbstract.java   |  62 +++++
 ...anagedObject.java => _ManagedObjectPacked.java} |  12 +-
 ...dObject.java => _ManagedObjectUnspecified.java} |  44 +---
 .../object/_ManagedObjectWithBookmark.java         | 170 ++++++++++++
 .../object/_ManagedObjectWithEagerSpec.java        |  71 ++++++
 .../object/_ManagedObjectWithLazySpec.java         |  77 ++++++
 .../core/metamodel/spec/feature/ObjectAction.java  |   4 +-
 .../core/metamodel/util/snapshot/XmlSnapshot.java  |   2 +-
 .../domainobjects/ObjectActionReprRenderer.java    |   4 +-
 .../domainobjects/ObjectAndActionInvocation.java   |   4 +-
 .../resources/ObjectAdapterUpdateHelper.java       |   4 +-
 .../entity/icontitle/EntityIconAndTitlePanel.java  |   5 +-
 15 files changed, 421 insertions(+), 428 deletions(-)

diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/ManagedObject.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/ManagedObject.java
index 15b49dd0d9..ed7e9a26cf 100644
--- 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/ManagedObject.java
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/ManagedObject.java
@@ -18,10 +18,7 @@
  */
 package org.apache.isis.core.metamodel.object;
 
-import java.util.Objects;
 import java.util.Optional;
-import java.util.UUID;
-import java.util.function.Function;
 import java.util.function.Supplier;
 import java.util.function.UnaryOperator;
 
@@ -30,25 +27,16 @@ import org.springframework.lang.Nullable;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.applib.value.semantics.Renderer;
 import org.apache.isis.commons.internal.assertions._Assert;
-import org.apache.isis.commons.internal.base._Lazy;
 import org.apache.isis.commons.internal.collections._Collections;
-import org.apache.isis.commons.internal.debug._XrayEvent;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
-import org.apache.isis.core.metamodel.context.MetaModelContext;
+import org.apache.isis.core.metamodel.context.HasMetaModelContext;
 import org.apache.isis.core.metamodel.facets.object.icon.ObjectIcon;
 import org.apache.isis.core.metamodel.facets.object.title.TitleRenderRequest;
-import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
-import org.apache.isis.core.metamodel.objectmanager.ObjectManager;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectFeature;
 import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 
-import lombok.AccessLevel;
-import lombok.AllArgsConstructor;
-import lombok.EqualsAndHashCode;
-import lombok.Getter;
 import lombok.NonNull;
-import lombok.ToString;
 import lombok.val;
 
 /**
@@ -56,7 +44,7 @@ import lombok.val;
  * that is IoC-container provided beans, persistence-stack provided entities 
or view-models.
  *
  */
-public interface ManagedObject {
+public interface ManagedObject extends HasMetaModelContext {
 
     /**
      * Returns the specification that details the structure (meta-model) of 
this object.
@@ -94,24 +82,10 @@ public interface ManagedObject {
 
     boolean isBookmarkMemoized();
 
-    default Supplier<ManagedObject> asProvider() {
-        return ()->this;
-    }
+    Supplier<ManagedObject> asSupplier();
 
-    /** debug */
-    default void assertSpecIsInSyncWithPojo() {
-//        val pojo = getPojo();
-//        val spec = getSpecification();
-//        if(pojo==null
-//                || spec==null) {
-//            return;
-//        }
-//        val actualSpec = 
spec.getSpecificationLoader().specForType(pojo.getClass()).orElse(null);
-//        if(!Objects.equals(spec,  actualSpec)) {
-//            System.err.printf("spec mismatch %s %s%n", spec, actualSpec);
-//        }
-        //_Assert.assertEquals(spec, actualSpec);
-    }
+    @Deprecated
+    void assertSpecIsInSyncWithPojo();
 
     // -- HTML
 
@@ -155,20 +129,6 @@ public interface ManagedObject {
                 .build());
     }
 
-    // -- SHORTCUTS - MM CONTEXT
-
-    default MetaModelContext getMetaModelContext() {
-        return ManagedObjects.spec(this)
-                .map(ObjectSpecification::getMetaModelContext)
-                .orElseThrow(()->_Exceptions
-                        .illegalArgument("Can only retrieve MetaModelContext 
from ManagedObjects "
-                                + "that have an ObjectSpecification."));
-    }
-
-    default ObjectManager getObjectManager() {
-        return getMetaModelContext().getObjectManager();
-    }
-
     // -- SHORTCUT - ELEMENT SPECIFICATION
 
     /**
@@ -205,7 +165,7 @@ public interface ManagedObject {
     public static ManagedObject notBookmarked(
             final ObjectSpecification spec,
             final Object pojo) {
-        return SimpleManagedObject.of(spec, pojo);
+        return _ManagedObjectWithEagerSpec.of(spec, pojo);
     }
 
     /**
@@ -248,7 +208,7 @@ public interface ManagedObject {
                     spec.getCorrespondingClass(), pojo.getClass(), 
pojo.toString());
         }
         ManagedObjects.assertPojoNotWrapped(pojo);
-        return SimpleManagedObject.identified(spec, pojo, bookmark);
+        return _ManagedObjectWithEagerSpec.identified(spec, pojo, bookmark);
     }
 
     /**
@@ -265,243 +225,19 @@ public interface ManagedObject {
         }
 
         ManagedObjects.assertPojoNotWrapped(pojo);
-        val adapter = new 
LazyManagedObject(cls->specLoader.specForType(cls).orElse(null), pojo);
+        val adapter = new 
_ManagedObjectWithLazySpec(cls->specLoader.specForType(cls).orElse(null), pojo);
         //ManagedObjects.warnIfAttachedEntity(adapter, "consider using 
ManagedObject.identified(...) for entity");
         return adapter;
     }
 
-    // -- EMPTY
-
     /** has no ObjectSpecification and no value (pojo) */
     static ManagedObject unspecified() {
-        return ManagedObjects.UNSPECIFIED;
+        return _ManagedObjectAbstract.UNSPECIFIED;
     }
 
     /** has an ObjectSpecification, but no value (pojo) */
     static ManagedObject empty(final @NonNull ObjectSpecification spec) {
-        return SimpleManagedObject.of(spec, null);
-    }
-
-    // -- LAZY BOOKMARK HANDLING
-
-    static abstract class ManagedObjectWithBookmark
-    implements ManagedObject {
-
-        protected final _Lazy<Optional<Bookmark>> bookmarkLazy =
-                _Lazy.threadSafe(()->bookmark(this));
-
-        @Override
-        public final Optional<Bookmark> getBookmark() {
-            return bookmarkLazy.get();
-        }
-
-        @Override
-        public final boolean isBookmarkMemoized() {
-            return bookmarkLazy.isMemoized();
-        }
-
-        @Override
-        public final Optional<Bookmark> getBookmarkRefreshed() {
-            // silently ignore invalidation, when the pojo is an entity
-            if(!getSpecification().isEntity()) {
-                bookmarkLazy.clear();
-            }
-            return getBookmark();
-        }
-
-        private void replaceBookmark(final UnaryOperator<Bookmark> replacer) {
-            final Bookmark old = bookmarkLazy.isMemoized()
-                    ? bookmarkLazy.get().orElse(null)
-                    : null;
-            bookmarkLazy.clear();
-            bookmarkLazy.set(Optional.ofNullable(replacer.apply(old)));
-        }
-
-        // guards against non-identifiable objects;
-        // historically, we allowed non-identifiable to be handled by the 
objectManager,
-        // which as a fallback creates 'random' UUIDs
-        private Optional<Bookmark> bookmark(final @Nullable ManagedObject 
adapter) {
-
-            if(ManagedObjects.isNullOrUnspecifiedOrEmpty(adapter)
-                    || adapter.getSpecification().isValue()
-                    || !ManagedObjects.isIdentifiable(adapter)) {
-                return Optional.empty();
-            }
-
-            return ManagedObjects.spec(adapter)
-                    .map(ObjectSpecification::getMetaModelContext)
-                    .map(MetaModelContext::getObjectManager)
-                    .map(objectManager->objectManager.bookmarkObject(adapter));
-        }
-
-        // -- REFRESH OPTIMIZATION
-
-        private UUID interactionIdDuringWhichRefreshed = null;
-
-        @Override
-        public final void refreshViewmodel(final @Nullable Supplier<Bookmark> 
bookmarkSupplier) {
-            val spec = getSpecification();
-            if(spec.isViewModel()) {
-                val viewModelFacet = spec.getFacet(ViewModelFacet.class);
-                if(viewModelFacet.containsEntities()) {
-
-                    val shouldRefresh = 
spec.getMetaModelContext().getInteractionProvider().getInteractionId()
-                    .map(this::shouldRefresh)
-                    .orElse(true); // if there is no current interaction, 
refresh regardless; unexpected state, might fail later
-
-                    if(!shouldRefresh) {
-                        return;
-                    }
-
-                    if(isBookmarkMemoized()) {
-                        reloadViewmodelFromMemoizedBookmark();
-                    } else {
-                        val bookmark = bookmarkSupplier!=null
-                                ? bookmarkSupplier.get()
-                                : null;
-                        if(bookmark!=null) {
-                            reloadViewmodelFromBookmark(bookmark);
-                        }
-                    }
-                }
-            }
-        }
-
-        private boolean shouldRefresh(final @NonNull UUID interactionId) {
-            if(Objects.equals(this.interactionIdDuringWhichRefreshed, 
interactionId)) {
-                return false; // already refreshed within current interaction
-            }
-            this.interactionIdDuringWhichRefreshed = interactionId;
-            return true;
-        }
-
-        /**
-         * Reload current viewmodel object from memoized bookmark, otherwise 
does nothing.
-         */
-        private void reloadViewmodelFromMemoizedBookmark() {
-            val spec = getSpecification();
-            if(isBookmarkMemoized()
-                    && spec.isViewModel()) {
-
-                val bookmark = getBookmark().get();
-                val viewModelClass = spec.getCorrespondingClass();
-
-                val recreatedViewmodel =
-                        
getMetaModelContext().getFactoryService().viewModel(viewModelClass, bookmark);
-
-                _XrayEvent.event("Viewmodel '%s' recreated from memoized 
bookmark.", viewModelClass.getName());
-
-                replacePojo(old->recreatedViewmodel);
-            }
-        }
-
-        private void reloadViewmodelFromBookmark(final @NonNull Bookmark 
bookmark) {
-            val spec = getSpecification();
-            if(spec.isViewModel()) {
-                val viewModelClass = spec.getCorrespondingClass();
-
-                val recreatedViewmodel =
-                        
getMetaModelContext().getFactoryService().viewModel(viewModelClass, bookmark);
-
-                _XrayEvent.event("Viewmodel '%s' recreated from provided 
bookmark.", viewModelClass.getName());
-
-                replacePojo(old->recreatedViewmodel);
-                replaceBookmark(old->bookmark);
-            }
-        }
-
-        /**
-         * Introduced, so we can re-fetch detached entity pojos in place.
-         */
-        abstract void replacePojo(UnaryOperator<Object> replacer);
-
-    }
-
-    // -- SIMPLE
-
-    //@Value
-    //@RequiredArgsConstructor(staticName="of", access = AccessLevel.PRIVATE)
-    @AllArgsConstructor(staticName="of", access = AccessLevel.PRIVATE)
-    @EqualsAndHashCode(of = "pojo", callSuper = false)
-    @ToString(of = {"specification", "pojo"}) //ISIS-2317 make sure toString() 
is without side-effects
-    @Getter
-    static final class SimpleManagedObject
-    extends ManagedObjectWithBookmark {
-
-        public static ManagedObject identified(
-                final @NonNull  ObjectSpecification spec,
-                final @Nullable Object pojo,
-                final @NonNull  Bookmark bookmark) {
-
-            if(pojo!=null) {
-                
_Assert.assertFalse(_Collections.isCollectionOrArrayOrCanType(pojo.getClass()));
-            }
-
-            val managedObject = SimpleManagedObject.of(spec, pojo);
-            managedObject.bookmarkLazy.set(Optional.of(bookmark));
-            return managedObject;
-        }
-
-        @NonNull private final ObjectSpecification specification;
-        @Nullable private /*final*/ Object pojo;
-
-        @Override
-        public void replacePojo(final UnaryOperator<Object> replacer) {
-            pojo = replacer.apply(pojo);
-            assertSpecIsInSyncWithPojo();
-        }
-
-    }
-
-    // -- LAZY
-
-    @EqualsAndHashCode(of = "pojo", callSuper = false)
-    static final class LazyManagedObject
-    extends ManagedObjectWithBookmark {
-
-        @NonNull private final Function<Class<?>, ObjectSpecification> 
specLoader;
-
-        @Getter @NonNull private /*final*/ Object pojo;
-
-        private final _Lazy<ObjectSpecification> specification = 
_Lazy.threadSafe(this::loadSpec);
-
-        public LazyManagedObject(
-                final @NonNull Function<Class<?>, ObjectSpecification> 
specLoader,
-                final @NonNull Object pojo) {
-            this.specLoader = specLoader;
-            this.pojo = pojo;
-        }
-
-        @Override
-        public ObjectSpecification getSpecification() {
-            return specification.get();
-        }
-
-        @Override //ISIS-2317 make sure toString() is without side-effects
-        public String toString() {
-            if(specification.isMemoized()) {
-                return String.format("ManagedObject[spec=%s, pojo=%s]",
-                        ""+getSpecification(),
-                        ""+getPojo());
-            }
-            return String.format("ManagedObject[spec=%s, pojo=%s]",
-                    "[lazy not loaded]",
-                    ""+getPojo());
-        }
-
-        private ObjectSpecification loadSpec() {
-            return specLoader.apply(pojo.getClass());
-        }
-
-        @Override
-        public void replacePojo(final UnaryOperator<Object> replacer) {
-            pojo = replacer.apply(pojo);
-            if(specification.isMemoized()) {
-                assertSpecIsInSyncWithPojo();
-            }
-        }
-
+        return _ManagedObjectWithEagerSpec.of(spec, null);
     }
 
-
 }
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/ManagedObjects.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/ManagedObjects.java
index 7729f7593f..d98f698b5a 100644
--- 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/ManagedObjects.java
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/ManagedObjects.java
@@ -62,7 +62,6 @@ import 
org.apache.isis.core.metamodel.interactions.InteractionHead;
 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.object.ManagedObject.ManagedObjectWithBookmark;
 import org.apache.isis.core.metamodel.objectmanager.load.ObjectLoader;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
@@ -151,6 +150,10 @@ public final class ManagedObjects {
 
     // -- INSTANCE-OF CHECKS
 
+    public static boolean isPacked(final @Nullable ManagedObject 
managedObject) {
+        return managedObject instanceof PackedManagedObject;
+    }
+
     /**
      * Whether given {@code object} is an instance of given {@code 
elementType}.
      */
@@ -499,41 +502,6 @@ public final class ManagedObjects {
         return result;
     }
 
-    // -- UNSPECIFIED OBJECT
-
-    static final ManagedObject UNSPECIFIED = new ManagedObject() {
-
-        @Override
-        public ObjectSpecification getSpecification() {
-            throw _Exceptions.unsupportedOperation();
-        }
-
-        @Override
-        public Object getPojo() {
-            return null;
-        }
-
-        @Override
-        public Optional<Bookmark> getBookmark() {
-            return Optional.empty();
-        }
-
-        @Override
-        public Optional<Bookmark> getBookmarkRefreshed() {
-            return Optional.empty();
-        }
-
-        @Override
-        public boolean isBookmarkMemoized() {
-            return false;
-        }
-
-        @Override
-        public void refreshViewmodel(final @Nullable Supplier<Bookmark> 
bookmarkSupplier) {
-            // noop; only available for viewmodels
-        }
-    };
-
     // -- SPECIFICATION UTILITIES
 
     /**
@@ -770,7 +738,7 @@ public final class ManagedObjects {
             val newState = EntityUtil.getEntityState(reattached);
             _Assert.assertTrue(newState.isAttached());
 
-            _Casts.castTo(ManagedObjectWithBookmark.class, managedObject)
+            _Casts.castTo(_ManagedObjectWithBookmark.class, managedObject)
             .ifPresent(obj->obj.replacePojo(old->reattached.getPojo()));
 
             return managedObject;
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/PackedManagedObject.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/PackedManagedObject.java
index d335b406e0..590c5ab8c0 100644
--- 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/PackedManagedObject.java
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/PackedManagedObject.java
@@ -18,74 +18,18 @@
  */
 package org.apache.isis.core.metamodel.object;
 
-import java.util.Collections;
-import java.util.Optional;
-import java.util.function.Supplier;
-import java.util.stream.Collectors;
-
-import org.springframework.lang.Nullable;
-
-import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.commons.collections.Can;
-import org.apache.isis.commons.internal.base._Lazy;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 
-import lombok.RequiredArgsConstructor;
-import lombok.ToString;
-
-@RequiredArgsConstructor
-@ToString
-public final class PackedManagedObject implements ManagedObject {
-
-    final ObjectSpecification elementSpec;
-    final Can<ManagedObject> nonScalar;
+public interface PackedManagedObject
+extends ManagedObject {
 
     public static ManagedObject pack(
             final ObjectSpecification elementSpec,
             final Can<ManagedObject> nonScalar) {
-        return new PackedManagedObject(elementSpec, nonScalar);
-    }
-
-    @Override
-    public ObjectSpecification getSpecification() {
-        return elementSpec;
-    }
-
-    @Override
-    public Object getPojo() {
-        return Collections.unmodifiableList(
-                nonScalar.stream()
-                .map(ManagedObject::getPojo)
-                .collect(Collectors.toList()));
-    }
-
-    private final _Lazy<Optional<Bookmark>> bookmarkLazy =
-            _Lazy.threadSafe(()->{
-                return 
Optional.of(getSpecification().getMetaModelContext().getObjectManager().bookmarkObject(this));
-            });
-
-    @Override
-    public Optional<Bookmark> getBookmark() {
-        return bookmarkLazy.get();
+        return new _ManagedObjectPacked(elementSpec, nonScalar);
     }
 
-    @Override
-    public Optional<Bookmark> getBookmarkRefreshed() {
-        return getBookmark(); // no-effect
-    }
-
-    @Override
-    public boolean isBookmarkMemoized() {
-        return bookmarkLazy.isMemoized();
-    }
-
-    public Can<ManagedObject> unpack(){
-        return nonScalar;
-    }
-
-    @Override
-    public void refreshViewmodel(final @Nullable Supplier<Bookmark> 
bookmarkSupplier) {
-        // noop; only available for viewmodels
-    }
+    Can<ManagedObject> unpack();
 
 }
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectAbstract.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectAbstract.java
new file mode 100644
index 0000000000..f6cd5842d1
--- /dev/null
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectAbstract.java
@@ -0,0 +1,62 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.core.metamodel.object;
+
+import java.util.function.Supplier;
+
+import org.apache.isis.commons.internal.exceptions._Exceptions;
+import org.apache.isis.core.metamodel.context.MetaModelContext;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+
+abstract class _ManagedObjectAbstract
+implements ManagedObject {
+
+    static final ManagedObject UNSPECIFIED = new _ManagedObjectUnspecified();
+
+    @Override
+    public final MetaModelContext getMetaModelContext() {
+        return ManagedObjects.spec(this)
+                .map(ObjectSpecification::getMetaModelContext)
+                .orElseThrow(()->_Exceptions
+                        .illegalArgument("Can only retrieve MetaModelContext 
from ManagedObjects "
+                                + "that have an ObjectSpecification."));
+    }
+
+    @Override
+    public final Supplier<ManagedObject> asSupplier() {
+        return ()->this;
+    }
+
+    /** debug */
+    @Override
+    public void assertSpecIsInSyncWithPojo() {
+//        val pojo = getPojo();
+//        val spec = getSpecification();
+//        if(pojo==null
+//                || spec==null) {
+//            return;
+//        }
+//        val actualSpec = 
spec.getSpecificationLoader().specForType(pojo.getClass()).orElse(null);
+//        if(!Objects.equals(spec,  actualSpec)) {
+//            System.err.printf("spec mismatch %s %s%n", spec, actualSpec);
+//        }
+        //_Assert.assertEquals(spec, actualSpec);
+    }
+
+}
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/PackedManagedObject.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectPacked.java
similarity index 88%
copy from 
core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/PackedManagedObject.java
copy to 
core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectPacked.java
index d335b406e0..8bba1b6e56 100644
--- 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/PackedManagedObject.java
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectPacked.java
@@ -35,17 +35,13 @@ import lombok.ToString;
 
 @RequiredArgsConstructor
 @ToString
-public final class PackedManagedObject implements ManagedObject {
+final class _ManagedObjectPacked
+extends _ManagedObjectAbstract
+implements PackedManagedObject {
 
     final ObjectSpecification elementSpec;
     final Can<ManagedObject> nonScalar;
 
-    public static ManagedObject pack(
-            final ObjectSpecification elementSpec,
-            final Can<ManagedObject> nonScalar) {
-        return new PackedManagedObject(elementSpec, nonScalar);
-    }
-
     @Override
     public ObjectSpecification getSpecification() {
         return elementSpec;
@@ -79,13 +75,13 @@ public final class PackedManagedObject implements 
ManagedObject {
         return bookmarkLazy.isMemoized();
     }
 
+    @Override
     public Can<ManagedObject> unpack(){
         return nonScalar;
     }
 
     @Override
     public void refreshViewmodel(final @Nullable Supplier<Bookmark> 
bookmarkSupplier) {
-        // noop; only available for viewmodels
     }
 
 }
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/PackedManagedObject.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectUnspecified.java
similarity index 54%
copy from 
core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/PackedManagedObject.java
copy to 
core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectUnspecified.java
index d335b406e0..d74e9f5cbf 100644
--- 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/PackedManagedObject.java
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectUnspecified.java
@@ -18,74 +18,44 @@
  */
 package org.apache.isis.core.metamodel.object;
 
-import java.util.Collections;
 import java.util.Optional;
 import java.util.function.Supplier;
-import java.util.stream.Collectors;
 
 import org.springframework.lang.Nullable;
 
 import org.apache.isis.applib.services.bookmark.Bookmark;
-import org.apache.isis.commons.collections.Can;
-import org.apache.isis.commons.internal.base._Lazy;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 
-import lombok.RequiredArgsConstructor;
-import lombok.ToString;
-
-@RequiredArgsConstructor
-@ToString
-public final class PackedManagedObject implements ManagedObject {
-
-    final ObjectSpecification elementSpec;
-    final Can<ManagedObject> nonScalar;
-
-    public static ManagedObject pack(
-            final ObjectSpecification elementSpec,
-            final Can<ManagedObject> nonScalar) {
-        return new PackedManagedObject(elementSpec, nonScalar);
-    }
+final class _ManagedObjectUnspecified extends _ManagedObjectAbstract {
 
     @Override
     public ObjectSpecification getSpecification() {
-        return elementSpec;
+        throw _Exceptions.unsupportedOperation();
     }
 
     @Override
     public Object getPojo() {
-        return Collections.unmodifiableList(
-                nonScalar.stream()
-                .map(ManagedObject::getPojo)
-                .collect(Collectors.toList()));
+        return null;
     }
 
-    private final _Lazy<Optional<Bookmark>> bookmarkLazy =
-            _Lazy.threadSafe(()->{
-                return 
Optional.of(getSpecification().getMetaModelContext().getObjectManager().bookmarkObject(this));
-            });
-
     @Override
     public Optional<Bookmark> getBookmark() {
-        return bookmarkLazy.get();
+        return Optional.empty();
     }
 
     @Override
     public Optional<Bookmark> getBookmarkRefreshed() {
-        return getBookmark(); // no-effect
+        return Optional.empty();
     }
 
     @Override
     public boolean isBookmarkMemoized() {
-        return bookmarkLazy.isMemoized();
-    }
-
-    public Can<ManagedObject> unpack(){
-        return nonScalar;
+        return false;
     }
 
     @Override
     public void refreshViewmodel(final @Nullable Supplier<Bookmark> 
bookmarkSupplier) {
-        // noop; only available for viewmodels
     }
 
 }
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectWithBookmark.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectWithBookmark.java
new file mode 100644
index 0000000000..50e0ddd12f
--- /dev/null
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectWithBookmark.java
@@ -0,0 +1,170 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.core.metamodel.object;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.function.Supplier;
+import java.util.function.UnaryOperator;
+
+import org.springframework.lang.Nullable;
+
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.commons.internal.base._Lazy;
+import org.apache.isis.commons.internal.debug._XrayEvent;
+import org.apache.isis.core.metamodel.context.MetaModelContext;
+import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+
+import lombok.NonNull;
+import lombok.val;
+
+abstract class _ManagedObjectWithBookmark
+extends _ManagedObjectAbstract {
+
+    protected final _Lazy<Optional<Bookmark>> bookmarkLazy =
+            _Lazy.threadSafe(()->bookmark(this));
+
+    @Override
+    public final Optional<Bookmark> getBookmark() {
+        return bookmarkLazy.get();
+    }
+
+    @Override
+    public final boolean isBookmarkMemoized() {
+        return bookmarkLazy.isMemoized();
+    }
+
+    @Override
+    public final Optional<Bookmark> getBookmarkRefreshed() {
+        // silently ignore invalidation, when the pojo is an entity
+        if(!getSpecification().isEntity()) {
+            bookmarkLazy.clear();
+        }
+        return getBookmark();
+    }
+
+    private void replaceBookmark(final UnaryOperator<Bookmark> replacer) {
+        final Bookmark old = bookmarkLazy.isMemoized()
+                ? bookmarkLazy.get().orElse(null)
+                : null;
+        bookmarkLazy.clear();
+        bookmarkLazy.set(Optional.ofNullable(replacer.apply(old)));
+    }
+
+    // guards against non-identifiable objects;
+    // historically, we allowed non-identifiable to be handled by the 
objectManager,
+    // which as a fallback creates 'random' UUIDs
+    private Optional<Bookmark> bookmark(final @Nullable ManagedObject adapter) 
{
+
+        if(ManagedObjects.isNullOrUnspecifiedOrEmpty(adapter)
+                || adapter.getSpecification().isValue()
+                || !ManagedObjects.isIdentifiable(adapter)) {
+            return Optional.empty();
+        }
+
+        return ManagedObjects.spec(adapter)
+                .map(ObjectSpecification::getMetaModelContext)
+                .map(MetaModelContext::getObjectManager)
+                .map(objectManager->objectManager.bookmarkObject(adapter));
+    }
+
+    // -- REFRESH OPTIMIZATION
+
+    private UUID interactionIdDuringWhichRefreshed = null;
+
+    @Override
+    public final void refreshViewmodel(final @Nullable Supplier<Bookmark> 
bookmarkSupplier) {
+        val spec = getSpecification();
+        if(spec.isViewModel()) {
+            val viewModelFacet = spec.getFacet(ViewModelFacet.class);
+            if(viewModelFacet.containsEntities()) {
+
+                val shouldRefresh = 
spec.getMetaModelContext().getInteractionProvider().getInteractionId()
+                .map(this::shouldRefresh)
+                .orElse(true); // if there is no current interaction, refresh 
regardless; unexpected state, might fail later
+
+                if(!shouldRefresh) {
+                    return;
+                }
+
+                if(isBookmarkMemoized()) {
+                    reloadViewmodelFromMemoizedBookmark();
+                } else {
+                    val bookmark = bookmarkSupplier!=null
+                            ? bookmarkSupplier.get()
+                            : null;
+                    if(bookmark!=null) {
+                        reloadViewmodelFromBookmark(bookmark);
+                    }
+                }
+            }
+        }
+    }
+
+    private boolean shouldRefresh(final @NonNull UUID interactionId) {
+        if(Objects.equals(this.interactionIdDuringWhichRefreshed, 
interactionId)) {
+            return false; // already refreshed within current interaction
+        }
+        this.interactionIdDuringWhichRefreshed = interactionId;
+        return true;
+    }
+
+    /**
+     * Reload current viewmodel object from memoized bookmark, otherwise does 
nothing.
+     */
+    private void reloadViewmodelFromMemoizedBookmark() {
+        val spec = getSpecification();
+        if(isBookmarkMemoized()
+                && spec.isViewModel()) {
+
+            val bookmark = getBookmark().get();
+            val viewModelClass = spec.getCorrespondingClass();
+
+            val recreatedViewmodel =
+                    
getMetaModelContext().getFactoryService().viewModel(viewModelClass, bookmark);
+
+            _XrayEvent.event("Viewmodel '%s' recreated from memoized 
bookmark.", viewModelClass.getName());
+
+            replacePojo(old->recreatedViewmodel);
+        }
+    }
+
+    private void reloadViewmodelFromBookmark(final @NonNull Bookmark bookmark) 
{
+        val spec = getSpecification();
+        if(spec.isViewModel()) {
+            val viewModelClass = spec.getCorrespondingClass();
+
+            val recreatedViewmodel =
+                    
getMetaModelContext().getFactoryService().viewModel(viewModelClass, bookmark);
+
+            _XrayEvent.event("Viewmodel '%s' recreated from provided 
bookmark.", viewModelClass.getName());
+
+            replacePojo(old->recreatedViewmodel);
+            replaceBookmark(old->bookmark);
+        }
+    }
+
+    /**
+     * Introduced, so we can re-fetch detached entity pojos in place.
+     */
+    abstract void replacePojo(UnaryOperator<Object> replacer);
+
+}
\ No newline at end of file
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectWithEagerSpec.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectWithEagerSpec.java
new file mode 100644
index 0000000000..923b4ecb92
--- /dev/null
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectWithEagerSpec.java
@@ -0,0 +1,71 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.core.metamodel.object;
+
+import java.util.Optional;
+import java.util.function.UnaryOperator;
+
+import org.springframework.lang.Nullable;
+
+import org.apache.isis.applib.services.bookmark.Bookmark;
+import org.apache.isis.commons.internal.assertions._Assert;
+import org.apache.isis.commons.internal.collections._Collections;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.ToString;
+import lombok.val;
+
+//@Value
+//@RequiredArgsConstructor(staticName="of", access = AccessLevel.PRIVATE)
+@AllArgsConstructor(staticName="of", access = AccessLevel.PACKAGE)
+@EqualsAndHashCode(of = "pojo", callSuper = false)
+@ToString(of = {"specification", "pojo"}) //ISIS-2317 make sure toString() is 
without side-effects
+@Getter
+final class _ManagedObjectWithEagerSpec
+extends _ManagedObjectWithBookmark {
+
+    public static ManagedObject identified(
+            final @NonNull  ObjectSpecification spec,
+            final @Nullable Object pojo,
+            final @NonNull  Bookmark bookmark) {
+
+        if(pojo!=null) {
+            
_Assert.assertFalse(_Collections.isCollectionOrArrayOrCanType(pojo.getClass()));
+        }
+
+        val managedObject = _ManagedObjectWithEagerSpec.of(spec, pojo);
+        managedObject.bookmarkLazy.set(Optional.of(bookmark));
+        return managedObject;
+    }
+
+    @NonNull private final ObjectSpecification specification;
+    @Nullable private /*final*/ Object pojo;
+
+    @Override
+    public void replacePojo(final UnaryOperator<Object> replacer) {
+        pojo = replacer.apply(pojo);
+        assertSpecIsInSyncWithPojo();
+    }
+
+}
\ No newline at end of file
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectWithLazySpec.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectWithLazySpec.java
new file mode 100644
index 0000000000..14d9d79fd5
--- /dev/null
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/object/_ManagedObjectWithLazySpec.java
@@ -0,0 +1,77 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.core.metamodel.object;
+
+import java.util.function.Function;
+import java.util.function.UnaryOperator;
+
+import org.apache.isis.commons.internal.base._Lazy;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.NonNull;
+
+@EqualsAndHashCode(of = "pojo", callSuper = false)
+final class _ManagedObjectWithLazySpec
+extends _ManagedObjectWithBookmark {
+
+    @NonNull private final Function<Class<?>, ObjectSpecification> specLoader;
+
+    @Getter @NonNull private /*final*/ Object pojo;
+
+    private final _Lazy<ObjectSpecification> specification = 
_Lazy.threadSafe(this::loadSpec);
+
+    public _ManagedObjectWithLazySpec(
+            final @NonNull Function<Class<?>, ObjectSpecification> specLoader,
+            final @NonNull Object pojo) {
+        this.specLoader = specLoader;
+        this.pojo = pojo;
+    }
+
+    @Override
+    public ObjectSpecification getSpecification() {
+        return specification.get();
+    }
+
+    @Override //ISIS-2317 make sure toString() is without side-effects
+    public String toString() {
+        if(specification.isMemoized()) {
+            return String.format("ManagedObject[spec=%s, pojo=%s]",
+                    ""+getSpecification(),
+                    ""+getPojo());
+        }
+        return String.format("ManagedObject[spec=%s, pojo=%s]",
+                "[lazy not loaded]",
+                ""+getPojo());
+    }
+
+    private ObjectSpecification loadSpec() {
+        return specLoader.apply(pojo.getClass());
+    }
+
+    @Override
+    public void replacePojo(final UnaryOperator<Object> replacer) {
+        pojo = replacer.apply(pojo);
+        if(specification.isMemoized()) {
+            assertSpecIsInSyncWithPojo();
+        }
+    }
+
+}
\ No newline at end of file
diff --git 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
index a7a22701e3..9618294070 100644
--- 
a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
+++ 
b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
@@ -355,7 +355,7 @@ public interface ObjectAction extends ObjectMember {
                             hasImperativeFaIcon->
                                 
ManagedObjects.isNullOrUnspecifiedOrEmpty(domainObject)
                                     ? null
-                                    : 
hasImperativeFaIcon.getCssClassFaFactory(domainObject.asProvider())))
+                                    : 
hasImperativeFaIcon.getCssClassFaFactory(domainObject.asSupplier())))
             .filter(_NullSafe::isPresent);
         }
 
@@ -410,7 +410,7 @@ public interface ObjectAction extends ObjectMember {
                 val mixinSpec = action.getDeclaringType();
                 val ownerSpec = mixeeAdapter.getSpecification();
                 return ownerSpec.lookupMixedInMember(mixinSpec)
-                        
.map(mixedInMember->mixedInMember.getFriendlyName(mixeeAdapter.asProvider()))
+                        
.map(mixedInMember->mixedInMember.getFriendlyName(mixeeAdapter.asSupplier()))
                         .orElseThrow(_Exceptions::unexpectedCodeReach);
             }
             return action.getFriendlyName(head::getOwner);
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 2d6046fde9..69e49b224f 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
@@ -665,7 +665,7 @@ public class XmlSnapshot implements Snapshot {
 
             // Skip field if we have seen the name already
             for (int j = 0; j < i; j++) {
-                if (Objects.equals(fieldName, 
fields.get(i).getFriendlyName(adapter.asProvider()))) {
+                if (Objects.equals(fieldName, 
fields.get(i).getFriendlyName(adapter.asSupplier()))) {
                     log.debug("objectToElement(NO): {} SKIPPED", log("field", 
fieldName));
                     continue eachField;
                 }
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 93796b25f4..8c7cfea9e6 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
@@ -147,8 +147,8 @@ extends AbstractObjectMemberReprRenderer<ObjectAction> {
         final JsonRepresentation paramRep = JsonRepresentation.newMap();
         paramRep.mapPutInt("num", paramMeta.getParameterIndex());
         paramRep.mapPutString("id", paramMeta.getId());
-        paramRep.mapPutString("name", 
paramMeta.getFriendlyName(objectAdapter.asProvider()));
-        paramRep.mapPut("description", 
paramMeta.getDescription(objectAdapter.asProvider()));
+        paramRep.mapPutString("name", 
paramMeta.getFriendlyName(objectAdapter.asSupplier()));
+        paramRep.mapPut("description", 
paramMeta.getDescription(objectAdapter.asSupplier()));
         final Object paramChoices = choicesFor(paramMod, paramNeg);
         if (paramChoices != null) {
             paramRep.mapPut("choices", paramChoices);
diff --git 
a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectAndActionInvocation.java
 
b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectAndActionInvocation.java
index ce3ebdc732..08b24303ac 100644
--- 
a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectAndActionInvocation.java
+++ 
b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectAndActionInvocation.java
@@ -24,7 +24,7 @@ import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._Lazy;
 import org.apache.isis.core.metamodel.interactions.managed.ActionInteraction;
 import org.apache.isis.core.metamodel.object.ManagedObject;
-import org.apache.isis.core.metamodel.object.PackedManagedObject;
+import org.apache.isis.core.metamodel.object.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.util.Facets;
@@ -77,7 +77,7 @@ public class ObjectAndActionInvocation {
         // which is introspected eagerly on application start and should be 
the binding contract
         val actualReturnTypeSpec = returnedAdapter.getSpecification();
 
-        if (returnedAdapter instanceof PackedManagedObject
+        if (ManagedObjects.isPacked(returnedAdapter)
                 || isVector(actualReturnTypeSpec)) {
 
             // though not strictly required, try to be consistent:  empty list 
vs populated list
diff --git 
a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/ObjectAdapterUpdateHelper.java
 
b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/ObjectAdapterUpdateHelper.java
index 193851266a..eafe14eb41 100644
--- 
a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/ObjectAdapterUpdateHelper.java
+++ 
b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/resources/ObjectAdapterUpdateHelper.java
@@ -119,9 +119,9 @@ public class ObjectAdapterUpdateHelper {
             // otherwise, is an error.
             final String invalidReason = 
propertiesMap.getString("x-ro-invalidReason");
             if(invalidReason != null) {
-                propertiesMap.mapPutString("x-ro-invalidReason", invalidReason 
+ "; " + property.getFriendlyName(objectAdapter.asProvider()));
+                propertiesMap.mapPutString("x-ro-invalidReason", invalidReason 
+ "; " + property.getFriendlyName(objectAdapter.asSupplier()));
             } else {
-                propertiesMap.mapPutString("x-ro-invalidReason", "Mandatory 
field(s) missing: " + property.getFriendlyName(objectAdapter.asProvider()));
+                propertiesMap.mapPutString("x-ro-invalidReason", "Mandatory 
field(s) missing: " + property.getFriendlyName(objectAdapter.asSupplier()));
             }
             allOk = false;
             return allOk;
diff --git 
a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/icontitle/EntityIconAndTitlePanel.java
 
b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/icontitle/EntityIconAndTitlePanel.java
index d1fc7d02ad..8a85327e66 100644
--- 
a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/icontitle/EntityIconAndTitlePanel.java
+++ 
b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/entity/icontitle/EntityIconAndTitlePanel.java
@@ -29,7 +29,6 @@ import org.apache.isis.commons.internal.base._Strings;
 import 
org.apache.isis.core.metamodel.facets.members.cssclassfa.CssClassFaFactory;
 import org.apache.isis.core.metamodel.object.ManagedObject;
 import org.apache.isis.core.metamodel.object.ManagedObjects;
-import org.apache.isis.core.metamodel.object.PackedManagedObject;
 import org.apache.isis.core.metamodel.object.ManagedObjects.EntityUtil;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
@@ -175,7 +174,7 @@ extends PanelAbstract<ManagedObject, ObjectAdapterModel> {
 
     private String determineTitle() {
         val managedObject = getModel().getObject();
-        return managedObject instanceof PackedManagedObject
+        return ManagedObjects.isPacked(managedObject)
                 ? "(multiple objects)"
                 : managedObject != null
                     ? 
managedObject.titleString(conf->conf.skipTitlePartEvaluator(this::isContextAdapter))
@@ -217,7 +216,7 @@ extends PanelAbstract<ManagedObject, ObjectAdapterModel> {
     private static boolean isNonEmptyAbstractScalar(final ManagedObject obj) {
         if(obj==null
                 || obj.getPojo()==null
-                || obj instanceof PackedManagedObject) {
+                || ManagedObjects.isPacked(obj)) {
             return false;
         }
         return obj.getSpecification().isAbstract();

Reply via email to