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/30 14:42:36 UTC

[isis] branch master updated: ISIS-2383: intermediate: re-model choice providers to use CanVector instead of Pojo Object Arrays

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 7dfd10e  ISIS-2383: intermediate: re-model choice providers to use CanVector<ManagedObject> instead of Pojo Object Arrays
7dfd10e is described below

commit 7dfd10e8e73386210f89f677b92a4e0e3eee939b
Author: Andi Huber <ah...@apache.org>
AuthorDate: Tue Jun 30 16:42:16 2020 +0200

    ISIS-2383: intermediate: re-model choice providers to use
    CanVector<ManagedObject> instead of Pojo Object Arrays
    
    - make the choice providers more robust against wrong choice spec types,
    by explicitly passing over the required spec
    - yet has some lines for debugging, to be removed later
---
 .../facets/fallback/ActionChoicesFacetNone.java    |   5 +-
 .../choices/ChoicesFacetFromBoundedAbstract.java   |  25 +++--
 .../facets/object/choices/ChoicesFacetUtils.java   |  42 --------
 .../object/choices/enums/ChoicesFacetEnum.java     |  16 ++-
 ...ingValueFacetUsingSemanticsProviderFactory.java |   2 +-
 .../facets/objectvalue/choices/ChoicesFacet.java   |  17 +--
 .../ActionParameterAutoCompleteFacet.java          |   2 +-
 .../ActionParameterAutoCompleteFacetViaMethod.java |  14 ++-
 .../facets/param/choices/ActionChoicesFacet.java   |   3 +-
 .../param/choices/ActionParameterChoicesFacet.java |   4 +-
 .../choices/ActionParameterChoicesFacetNone.java   |   6 +-
 ...rameterChoicesFacetDerivedFromChoicesFacet.java |   6 +-
 .../method/ActionChoicesFacetViaMethod.java        |  31 +++---
 .../ActionParameterChoicesFacetViaMethod.java      |  20 ++--
 .../properties/choices/PropertyChoicesFacet.java   |   3 +-
 ...ropertyChoicesFacetDerivedFromChoicesFacet.java |   6 +-
 .../method/PropertyChoicesFacetViaMethod.java      |  27 +++--
 ...arameterChoicesFacetFromParentedCollection.java |  10 +-
 .../isis/core/metamodel/spec/ManagedObject.java    |   6 +-
 .../isis/core/metamodel/spec/ManagedObjects.java   |  46 ++++++++
 .../core/metamodel/spec/ObjectSpecification.java   |  14 +--
 .../core/metamodel/spec/feature/ObjectAction.java  |   7 +-
 .../specloader/specimpl/ObjectActionDefault.java   | 117 +++++++++------------
 .../specloader/specimpl/ObjectActionMixedIn.java   |   3 +-
 .../specimpl/ObjectActionParameterAbstract.java    |  61 +++++------
 .../specimpl/OneToOneAssociationDefault.java       |   9 +-
 .../scalars/reference/ReferencePanel.java          |   2 +-
 .../mementos/ObjectMementoServiceWicket.java       |  31 +++++-
 28 files changed, 275 insertions(+), 260 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/fallback/ActionChoicesFacetNone.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/fallback/ActionChoicesFacetNone.java
index ff6993c..f3c50cd 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/fallback/ActionChoicesFacetNone.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/fallback/ActionChoicesFacetNone.java
@@ -19,6 +19,7 @@
 
 package org.apache.isis.core.metamodel.facets.fallback;
 
+import org.apache.isis.core.commons.collections.CanVector;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.param.choices.ActionChoicesFacetAbstract;
@@ -31,10 +32,10 @@ public class ActionChoicesFacetNone extends ActionChoicesFacetAbstract {
     }
 
     @Override
-    public Object[][] getChoices(
+    public CanVector<ManagedObject> getChoices(
             final ManagedObject inObject,
             final InteractionInitiatedBy interactionInitiatedBy) {
-        return new ManagedObject[0][0];
+        return CanVector.empty();
     }
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/choices/ChoicesFacetFromBoundedAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/choices/ChoicesFacetFromBoundedAbstract.java
index d8dfaff..0365088 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/choices/ChoicesFacetFromBoundedAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/choices/ChoicesFacetFromBoundedAbstract.java
@@ -19,8 +19,7 @@
 
 package org.apache.isis.core.metamodel.facets.object.choices;
 
-import java.util.function.Predicate;
-
+import org.apache.isis.core.commons.collections.Can;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facetapi.FacetAbstract;
@@ -31,6 +30,7 @@ import org.apache.isis.core.metamodel.interactions.ObjectValidityContext;
 import org.apache.isis.core.metamodel.interactions.UsabilityContext;
 import org.apache.isis.core.metamodel.interactions.ValidatingInteractionAdvisor;
 import org.apache.isis.core.metamodel.interactions.ValidityContext;
+import org.apache.isis.core.metamodel.objectmanager.query.ObjectBulkLoader;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
@@ -101,18 +101,21 @@ implements ChoicesFacet, DisablingInteractionAdvisor, ValidatingInteractionAdvis
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
     @Override
-    public Object[] getChoices(
+    public Can<ManagedObject> getChoices(
             ManagedObject adapter,
             final InteractionInitiatedBy interactionInitiatedBy) {
 
-        val context = getMetaModelContext();
-        val repository = context.getRepositoryService();
-
-        final Predicate<ManagedObject> visibilityFilter = 
-                objectAdapter -> ManagedObjects.VisibilityUtil.isVisible(objectAdapter, interactionInitiatedBy);
-
-        val query = new QueryFindAllChoices(getObjectSpecification().getFullIdentifier(), visibilityFilter, 0L, Long.MAX_VALUE);
-        return repository.allMatches(query).toArray();
+        val query = new QueryFindAllChoices(
+                getObjectSpecification().getFullIdentifier(), 
+                ManagedObjects.VisibilityUtil.filterOn(interactionInitiatedBy), 
+                0L, 
+                Long.MAX_VALUE);
+        
+        val resultTypeSpec = getObjectManager().loadSpecification(query.getResultType());
+        val queryRequest = ObjectBulkLoader.Request.of(resultTypeSpec, query);
+        val allMatching = getObjectManager().queryObjects(queryRequest);
+        
+        return allMatching;
     }
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/choices/ChoicesFacetUtils.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/choices/ChoicesFacetUtils.java
deleted file mode 100644
index 518cfbc..0000000
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/choices/ChoicesFacetUtils.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- *  Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- */
-
-package org.apache.isis.core.metamodel.facets.object.choices;
-
-import javax.enterprise.inject.Vetoed;
-
-import org.apache.isis.core.metamodel.facets.objectvalue.choices.ChoicesFacet;
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
-
-@Vetoed
-public class ChoicesFacetUtils {
-
-    private ChoicesFacetUtils() {
-    }
-
-    /**
-     *
-     * @deprecated - use {@link ChoicesFacet.Util}
-     */
-    @Deprecated
-    public static boolean hasChoices(final ObjectSpecification specification) {
-        return ChoicesFacet.Util.hasChoices(specification);
-    }
-
-}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/choices/enums/ChoicesFacetEnum.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/choices/enums/ChoicesFacetEnum.java
index 43cacd7..a7513b7 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/choices/enums/ChoicesFacetEnum.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/choices/enums/ChoicesFacetEnum.java
@@ -21,22 +21,30 @@ package org.apache.isis.core.metamodel.facets.object.choices.enums;
 
 import java.util.Map;
 
+import org.apache.isis.core.commons.collections.Can;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.objectvalue.choices.ChoicesFacetAbstract;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 
+import lombok.val;
+
 public class ChoicesFacetEnum extends ChoicesFacetAbstract {
 
-    private final Object[] choices;
+    private final Can<ManagedObject> choices;
 
-    public ChoicesFacetEnum(final FacetHolder holder, final Object[] choices) {
+    public ChoicesFacetEnum(final FacetHolder holder, final Class<?> enumClass) {
         super(holder);
-        this.choices = choices;
+        
+        final Object[] choices = enumClass.getEnumConstants();
+        
+        val elementSpec = getSpecification(enumClass);
+        this.choices = Can.ofArray(choices)
+                .map(choice->ManagedObject.of(elementSpec, choice));
     }
 
     @Override
-    public Object[] getChoices(
+    public Can<ManagedObject> getChoices(
             final ManagedObject adapter,
             final InteractionInitiatedBy interactionInitiatedBy) {
         return choices;
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/choices/enums/EnumFacetUsingValueFacetUsingSemanticsProviderFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/choices/enums/EnumFacetUsingValueFacetUsingSemanticsProviderFactory.java
index b5e3130..a48ed18 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/choices/enums/EnumFacetUsingValueFacetUsingSemanticsProviderFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/choices/enums/EnumFacetUsingValueFacetUsingSemanticsProviderFactory.java
@@ -43,7 +43,7 @@ extends ValueFacetUsingSemanticsProviderFactory<Enum<?>> {
                 new EnumValueSemanticsProvider<>(holder, _Casts.uncheckedCast(cls));
         
         addFacets(_Casts.uncheckedCast(enumValueSemanticsProvider));
-        super.addFacet(new ChoicesFacetEnum(holder, cls.getEnumConstants()));
+        super.addFacet(new ChoicesFacetEnum(holder, cls));
     }
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/objectvalue/choices/ChoicesFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/objectvalue/choices/ChoicesFacet.java
index 7a2ac9e..e1f0334 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/objectvalue/choices/ChoicesFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/objectvalue/choices/ChoicesFacet.java
@@ -19,31 +19,18 @@
 
 package org.apache.isis.core.metamodel.facets.objectvalue.choices;
 
+import org.apache.isis.core.commons.collections.Can;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 
 public interface ChoicesFacet extends Facet {
 
     /**
      * Gets a set of choices for this object.
      */
-    public Object[] getChoices(
+    public Can<ManagedObject> getChoices(
             final ManagedObject adapter,
             final InteractionInitiatedBy interactionInitiatedBy);
 
-
-
-    public static class Util {
-
-        private Util() {
-        }
-
-        public static boolean hasChoices(final ObjectSpecification specification) {
-            return specification.getFacet(ChoicesFacet.class) != null;
-        }
-
-    }
-
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/autocomplete/ActionParameterAutoCompleteFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/autocomplete/ActionParameterAutoCompleteFacet.java
index a7a7e4b..f69def3 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/autocomplete/ActionParameterAutoCompleteFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/autocomplete/ActionParameterAutoCompleteFacet.java
@@ -34,7 +34,7 @@ import org.apache.isis.core.metamodel.spec.ManagedObject;
  */
 public interface ActionParameterAutoCompleteFacet extends Facet {
 
-    public Object[] autoComplete(
+    public Can<ManagedObject> autoComplete(
             ManagedObject inObject,
             Can<ManagedObject> pendingArgs,
             String searchArg,
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/autocomplete/method/ActionParameterAutoCompleteFacetViaMethod.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/autocomplete/method/ActionParameterAutoCompleteFacetViaMethod.java
index 1167bbd..bcb590c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/autocomplete/method/ActionParameterAutoCompleteFacetViaMethod.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/autocomplete/method/ActionParameterAutoCompleteFacetViaMethod.java
@@ -27,7 +27,6 @@ import java.util.Map;
 import java.util.Optional;
 
 import org.apache.isis.core.commons.collections.Can;
-import org.apache.isis.core.commons.internal._Constants;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.ImperativeFacet;
@@ -80,7 +79,7 @@ implements ImperativeFacet {
     }
 
     @Override
-    public Object[] autoComplete(
+    public Can<ManagedObject> autoComplete(
             final ManagedObject owningAdapter,
             final Can<ManagedObject> pendingArgs,
             final String searchArg,
@@ -93,14 +92,13 @@ implements ImperativeFacet {
                         method, owningAdapter, pendingArgs, Collections.singletonList(searchArg));
         
         if (collectionOrArray == null) {
-            return _Constants.emptyObjects;
+            return Can.empty();
         }
-        val collectionAdapter = getObjectManager().adapt(collectionOrArray);
-
-        val visiblePojos = ManagedObjects.VisibilityUtil
-                .visiblePojosAsArray(collectionAdapter, interactionInitiatedBy);
+        val elementSpec = getObjectManager().loadSpecification(choicesType);
+        val visibleChoices = ManagedObjects
+                .adaptMultipleOfTypeThenAttachThenFilterByVisibility(elementSpec, collectionOrArray, interactionInitiatedBy);
         
-        return visiblePojos;
+        return visibleChoices;
     }
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/ActionChoicesFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/ActionChoicesFacet.java
index b74d74a..6ce6f39 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/ActionChoicesFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/ActionChoicesFacet.java
@@ -19,6 +19,7 @@
 
 package org.apache.isis.core.metamodel.facets.param.choices;
 
+import org.apache.isis.core.commons.collections.CanVector;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
@@ -32,7 +33,7 @@ import org.apache.isis.core.metamodel.spec.ManagedObject;
  */
 public interface ActionChoicesFacet extends Facet {
 
-    public Object[][] getChoices(
+    public CanVector<ManagedObject> getChoices(
             final ManagedObject inObject,
             final InteractionInitiatedBy interactionInitiatedBy);
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/ActionParameterChoicesFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/ActionParameterChoicesFacet.java
index 653cbe7..4019b20 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/ActionParameterChoicesFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/ActionParameterChoicesFacet.java
@@ -23,6 +23,7 @@ import org.apache.isis.core.commons.collections.Can;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 
 /**
  * Obtain choices for each of the parameters of the action.
@@ -34,7 +35,8 @@ import org.apache.isis.core.metamodel.spec.ManagedObject;
  */
 public interface ActionParameterChoicesFacet extends Facet {
 
-    public Object[] getChoices(
+    public Can<ManagedObject> getChoices(
+            ObjectSpecification requiredSpec,
             ManagedObject target,
             Can<ManagedObject> pendingArgs,
             InteractionInitiatedBy interactionInitiatedBy);
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/ActionParameterChoicesFacetNone.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/ActionParameterChoicesFacetNone.java
index a4e1cae..c50d001 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/ActionParameterChoicesFacetNone.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/ActionParameterChoicesFacetNone.java
@@ -23,6 +23,7 @@ import org.apache.isis.core.commons.collections.Can;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 
 public class ActionParameterChoicesFacetNone extends ActionParameterChoicesFacetAbstract {
 
@@ -31,12 +32,13 @@ public class ActionParameterChoicesFacetNone extends ActionParameterChoicesFacet
     }
 
     @Override
-    public Object[] getChoices(
+    public Can<ManagedObject> getChoices(
+            final ObjectSpecification requiredSpec,
             final ManagedObject adapter,
             final Can<ManagedObject> pendingArgs,
             final InteractionInitiatedBy interactionInitiatedBy) {
         
-        return new ManagedObject[0];
+        return Can.empty();
     }
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/enums/ActionParameterChoicesFacetDerivedFromChoicesFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/enums/ActionParameterChoicesFacetDerivedFromChoicesFacet.java
index 6a0b222..19806c8 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/enums/ActionParameterChoicesFacetDerivedFromChoicesFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/enums/ActionParameterChoicesFacetDerivedFromChoicesFacet.java
@@ -20,7 +20,6 @@
 package org.apache.isis.core.metamodel.facets.param.choices.enums;
 
 import org.apache.isis.core.commons.collections.Can;
-import org.apache.isis.core.commons.internal._Constants;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.TypedHolder;
@@ -36,7 +35,8 @@ public class ActionParameterChoicesFacetDerivedFromChoicesFacet extends ActionPa
     }
 
     @Override
-    public Object[] getChoices(
+    public Can<ManagedObject> getChoices(
+            final ObjectSpecification requiredSpec,
             final ManagedObject adapter,
             final Can<ManagedObject> pendingArgs,
             final InteractionInitiatedBy interactionInitiatedBy) {
@@ -46,7 +46,7 @@ public class ActionParameterChoicesFacetDerivedFromChoicesFacet extends ActionPa
         final ObjectSpecification noSpec = getSpecification(paramPeer.getType());
         final ChoicesFacet choicesFacet = noSpec.getFacet(ChoicesFacet.class);
         if (choicesFacet == null) {
-            return _Constants.emptyObjects;
+            return Can.empty();
         }
         return choicesFacet.getChoices(adapter, interactionInitiatedBy);
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/method/ActionChoicesFacetViaMethod.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/method/ActionChoicesFacetViaMethod.java
index 2dd5c49..daa09aa 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/method/ActionChoicesFacetViaMethod.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/method/ActionChoicesFacetViaMethod.java
@@ -24,6 +24,8 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.isis.core.commons.collections.Can;
+import org.apache.isis.core.commons.collections.CanVector;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.ImperativeFacet;
@@ -64,9 +66,10 @@ public class ActionChoicesFacetViaMethod extends ActionChoicesFacetAbstract impl
     }
 
     @Override
-    public Object[][] getChoices(
+    public CanVector<ManagedObject> getChoices(
             final ManagedObject owningAdapter,
             final InteractionInitiatedBy interactionInitiatedBy) {
+        
         final Object objectOrCollection = ManagedObjects.InvokeUtil.invoke(method, owningAdapter);
         if (!(objectOrCollection instanceof Object[])) {
             throw new DomainModelException(String.format(
@@ -75,30 +78,26 @@ public class ActionChoicesFacetViaMethod extends ActionChoicesFacetAbstract impl
                             objectOrCollection));
         }
         final Object[] options = (Object[]) objectOrCollection;
-        final Object[][] results = new Object[options.length][];
-
+        
+        val choicesVector = new CanVector<ManagedObject>(options.length);
         val parameterTypes = method.getParameterTypes();
         
-        for (int i = 0; i < results.length; i++) {
-            results[i] = handleResults(options[i], parameterTypes[i], interactionInitiatedBy);
+        for (int i = 0; i < choicesVector.size(); i++) {
+            choicesVector.set(i, handleResults(options[i], parameterTypes[i], interactionInitiatedBy));
         }
-        return results;
+        return choicesVector;
     }
 
-    private Object[] handleResults(
+    private Can<ManagedObject> handleResults(
             final Object collectionOrArray,
             final Class<?> parameterType,
             final InteractionInitiatedBy interactionInitiatedBy) {
         
-        if (collectionOrArray == null) {
-            return null;
-        }
-
-        val collectionAdapter = getObjectManager().adapt(collectionOrArray);
-        val visiblePojos = ManagedObjects.VisibilityUtil
-                .visiblePojosAsArray(collectionAdapter, interactionInitiatedBy);
-        
-        return visiblePojos;
+        val elementSpec = getObjectManager().loadSpecification(parameterType);
+        val visibleChoices = ManagedObjects
+                .adaptMultipleOfTypeThenAttachThenFilterByVisibility(
+                        elementSpec, collectionOrArray, interactionInitiatedBy);
+        return visibleChoices;
     }
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/methodnum/ActionParameterChoicesFacetViaMethod.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/methodnum/ActionParameterChoicesFacetViaMethod.java
index c9c9893..18021236 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/methodnum/ActionParameterChoicesFacetViaMethod.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/choices/methodnum/ActionParameterChoicesFacetViaMethod.java
@@ -27,13 +27,13 @@ import java.util.Map;
 import java.util.Optional;
 
 import org.apache.isis.core.commons.collections.Can;
-import org.apache.isis.core.commons.internal._Constants;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.ImperativeFacet;
 import org.apache.isis.core.metamodel.facets.param.choices.ActionParameterChoicesFacetAbstract;
 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.val;
 
@@ -72,24 +72,24 @@ implements ImperativeFacet {
     }
 
     @Override
-    public Object[] getChoices(
+    public Can<ManagedObject> getChoices(
+            final ObjectSpecification requiredSpec,
             final ManagedObject owningAdapter,
             final Can<ManagedObject> pendingArgs,
             final InteractionInitiatedBy interactionInitiatedBy) {
         
-        final Object choices = ppmFactory.isPresent()
+        final Object collectionOrArray = ppmFactory.isPresent()
                 ? ManagedObjects.InvokeUtil.invokeWithPPM(ppmFactory.get(), method, owningAdapter, pendingArgs) 
                 : ManagedObjects.InvokeUtil.invokeAutofit(method, owningAdapter, pendingArgs);
-        if (choices == null) {
-            return _Constants.emptyObjects;
+        if (collectionOrArray == null) {
+            return Can.empty();
         }
         
-        val objectAdapter = getObjectManager().adapt(choices);
+        val visibleChoices = ManagedObjects
+                .adaptMultipleOfTypeThenAttachThenFilterByVisibility(
+                        requiredSpec, collectionOrArray, interactionInitiatedBy);
 
-        val visiblePojos = ManagedObjects.VisibilityUtil
-                .visiblePojosAsArray(objectAdapter, interactionInitiatedBy);
-
-        return visiblePojos;
+        return visibleChoices;
     }
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/choices/PropertyChoicesFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/choices/PropertyChoicesFacet.java
index 75c8896..cfd3c9b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/choices/PropertyChoicesFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/choices/PropertyChoicesFacet.java
@@ -19,6 +19,7 @@
 
 package org.apache.isis.core.metamodel.facets.properties.choices;
 
+import org.apache.isis.core.commons.collections.Can;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
@@ -44,7 +45,7 @@ public interface PropertyChoicesFacet extends Facet {
     /**
      * Gets the available choices for this property.
      */
-    public Object[] getChoices(
+    public Can<ManagedObject> getChoices(
             final ManagedObject adapter,
             final InteractionInitiatedBy interactionInitiatedBy);
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/choices/enums/PropertyChoicesFacetDerivedFromChoicesFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/choices/enums/PropertyChoicesFacetDerivedFromChoicesFacet.java
index 2464d85..73359d5 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/choices/enums/PropertyChoicesFacetDerivedFromChoicesFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/choices/enums/PropertyChoicesFacetDerivedFromChoicesFacet.java
@@ -19,7 +19,7 @@
 
 package org.apache.isis.core.metamodel.facets.properties.choices.enums;
 
-import org.apache.isis.core.commons.internal._Constants;
+import org.apache.isis.core.commons.collections.Can;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facets.FacetedMethod;
@@ -36,7 +36,7 @@ public class PropertyChoicesFacetDerivedFromChoicesFacet extends PropertyChoices
     }
 
     @Override
-    public Object[] getChoices(
+    public Can<ManagedObject> getChoices(
             final ManagedObject adapter,
             final InteractionInitiatedBy interactionInitiatedBy) {
 
@@ -44,7 +44,7 @@ public class PropertyChoicesFacetDerivedFromChoicesFacet extends PropertyChoices
         val methodSpec = getSpecification(facetedMethod.getType());
         val choicesFacet = methodSpec.getFacet(ChoicesFacet.class);
         if (choicesFacet == null) {
-            return _Constants.emptyObjects;
+            return Can.empty();
         }
         return choicesFacet.getChoices(adapter, interactionInitiatedBy);
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/choices/method/PropertyChoicesFacetViaMethod.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/choices/method/PropertyChoicesFacetViaMethod.java
index f447344..be8b49d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/choices/method/PropertyChoicesFacetViaMethod.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/properties/choices/method/PropertyChoicesFacetViaMethod.java
@@ -24,8 +24,12 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.isis.core.commons.collections.Can;
+import org.apache.isis.core.commons.internal.base._NullSafe;
+import org.apache.isis.core.commons.internal.debug._Probe;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.FacetedMethod;
 import org.apache.isis.core.metamodel.facets.ImperativeFacet;
 import org.apache.isis.core.metamodel.facets.properties.choices.PropertyChoicesFacetAbstract;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
@@ -63,22 +67,25 @@ public class PropertyChoicesFacetViaMethod extends PropertyChoicesFacetAbstract
     }
 
     @Override
-    public Object[] getChoices(
+    public Can<ManagedObject> getChoices(
             final ManagedObject owningAdapter,
             final InteractionInitiatedBy interactionInitiatedBy) {
         
+        val elementSpec = getObjectManager().loadSpecification(((FacetedMethod) getFacetHolder()).getType());
+        val optionPojos = ManagedObjects.InvokeUtil.invoke(method, owningAdapter);
         
-        final Object options = ManagedObjects.InvokeUtil.invoke(method, owningAdapter);
-        if (options == null) {
-            return null;
+        if(elementSpec.isEntity()) {
+            _NullSafe.streamAutodetect(optionPojos)
+            .map(pojo->ManagedObject.of(elementSpec, pojo))
+            .filter(adapter->!ManagedObjects.EntityUtil.isAttached(adapter))
+            .forEach(detached->_Probe.errOut("non attached entity from choices method %s detected", method));
         }
-
-        val collectionAdapter = getObjectManager().adapt(options);
-
-        val visiblePojos = ManagedObjects.VisibilityUtil
-                .visiblePojosAsArray(collectionAdapter, interactionInitiatedBy);
         
-        return visiblePojos;
+        
+        val visibleChoices = ManagedObjects
+                .adaptMultipleOfTypeThenAttachThenFilterByVisibility(elementSpec, optionPojos, interactionInitiatedBy);
+        
+        return visibleChoices;
     }
 
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/param/ActionParameterChoicesFacetFromParentedCollection.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/param/ActionParameterChoicesFacetFromParentedCollection.java
index 2ee412f..b88e47a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/param/ActionParameterChoicesFacetFromParentedCollection.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/param/ActionParameterChoicesFacetFromParentedCollection.java
@@ -28,6 +28,7 @@ import org.apache.isis.core.metamodel.facets.collections.CollectionFacet;
 import org.apache.isis.core.metamodel.facets.object.mixin.MixinFacet;
 import org.apache.isis.core.metamodel.facets.param.choices.ActionParameterChoicesFacetAbstract;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
 
 import lombok.val;
@@ -44,14 +45,15 @@ public class ActionParameterChoicesFacetFromParentedCollection extends ActionPar
     }
 
     @Override
-    public Object[] getChoices(
+    public Can<ManagedObject> getChoices(
+            final ObjectSpecification requiredSpec,
             final ManagedObject target,
             final Can<ManagedObject> pendingArgs,
             final InteractionInitiatedBy interactionInitiatedBy) {
 
-        final ManagedObject parentAdapter = determineParentAdapter(target);
-        final ManagedObject objectAdapter = otma.get(parentAdapter, interactionInitiatedBy);
-        return CollectionFacet.toArrayOfPojos(objectAdapter);
+        val parentAdapter = determineParentAdapter(target);
+        val objectAdapter = otma.get(parentAdapter, interactionInitiatedBy);
+        return CollectionFacet.streamAdapters(objectAdapter).collect(Can.toCan());
     }
 
     /**
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 70f4abd..d93fd75 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
@@ -110,9 +110,8 @@ public interface ManagedObject {
      * @return
      */
     public static ManagedObject of(@NonNull ObjectSpecification specification, @Nullable Object pojo) {
-        
+        ManagedObjects.assertPojoNotManaged(pojo);
         specification.assertPojoCompatible(pojo);
-        
         return new SimpleManagedObject(specification, pojo);
     }
     
@@ -128,6 +127,7 @@ public interface ManagedObject {
                     "pojo.toString() = %s",
                     specification.getCorrespondingClass(), pojo.getClass(), pojo.toString());
         }
+        ManagedObjects.assertPojoNotManaged(pojo);
         return SimpleManagedObject.identified(specification, pojo, rootOid);
     }
 
@@ -140,7 +140,7 @@ public interface ManagedObject {
     public static ManagedObject of(
             Function<Class<?>, ObjectSpecification> specLoader, 
             Object pojo) {
-
+        ManagedObjects.assertPojoNotManaged(pojo);
         return new LazyManagedObject(specLoader, pojo);
     }
     
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 d576897..f168d72 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
@@ -254,6 +254,48 @@ public final class ManagedObjects {
     private static String abbreviated(final String str, final int maxLength, String suffix) {
         return str.length() < maxLength ? str : str.substring(0, maxLength - 3) + suffix;
     }
+    
+    // -- ADABT UTILITIES
+    
+    public static Can<ManagedObject> adaptMultipleOfType(
+            @NonNull final ObjectSpecification elementSpec,
+            @Nullable final Object collectionOrArray) {
+        
+        return _NullSafe.streamAutodetect(collectionOrArray)
+        .map(pojo->ManagedObject.of(elementSpec, pojo)) // pojo is nullable here
+        .collect(Can.toCan());
+    }
+
+    /**
+     * used eg. to adapt the result of supporting methods, that return choice pojos
+     */
+    public static Can<ManagedObject> adaptMultipleOfTypeThenAttachThenFilterByVisibility(
+            @NonNull final ObjectSpecification elementSpec,
+            @Nullable final Object collectionOrArray, 
+            @NonNull  final InteractionInitiatedBy interactionInitiatedBy) {
+        
+        return _NullSafe.streamAutodetect(collectionOrArray)
+        .map(pojo->ManagedObject.of(elementSpec, pojo)) // pojo is nullable here
+//        .map(ManagedObjects.EntityUtil::reattach)
+        .filter(ManagedObjects.VisibilityUtil.filterOn(interactionInitiatedBy))
+        .collect(Can.toCan());
+    }
+    
+    public static void assertPojoNotManaged(@Nullable Object pojo) {
+        // can do this check only when the pojo is not null, otherwise is always considered valid
+        if(pojo==null) {
+            return;
+        }
+        
+        if(pojo instanceof ManagedObject) {
+            throw _Exceptions.illegalArgument(
+                    "Cannot adapt a pojo of type ManagedObject, " +
+                    "pojo.getClass() = %s, " +
+                    "pojo.toString() = %s",
+                    pojo.getClass(), pojo.toString());
+        }
+    }
+
 
     // -- ENTITY UTILITIES
     
@@ -338,6 +380,8 @@ public final class ManagedObjects {
                 return managedObject;
             }
             
+            //TODO identification fails, on detached object, if rootOid was not previously memoized 
+            
             val objectIdentifier = identify(managedObject)
                     .map(RootOid::getIdentifier);
                     
@@ -720,6 +764,8 @@ public final class ManagedObjects {
         }
         
     }
+
+
     
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecification.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecification.java
index cb17303..0c01962 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecification.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ObjectSpecification.java
@@ -465,8 +465,13 @@ public interface ObjectSpecification extends Specification, ObjectActionContaine
     // -- TYPE COMPATIBILITY UTILITIES
     
     default public void assertPojoCompatible(@Nullable Object pojo) {
+        
+        // can do this check only when the pojo is not null, otherwise is always considered valid
+        if(pojo==null) {
+            return;
+        }
+        
         if(!isPojoCompatible(pojo)) {
-            Objects.requireNonNull(pojo);
             val expectedType = getCorrespondingClass();
             throw _Exceptions.illegalArgument(
                     "Pojo not compatible with ObjectSpecification, " +
@@ -477,12 +482,7 @@ public interface ObjectSpecification extends Specification, ObjectActionContaine
         }
     }
     
-    default public boolean isPojoCompatible(@Nullable Object pojo) {
-        
-        // can do this check only when the pojo is not null, otherwise is always considered valid
-        if(pojo==null) {
-            return true;
-        }
+    default public boolean isPojoCompatible(Object pojo) {
         
         val expectedType = getCorrespondingClass();
         val actualType = pojo.getClass();
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 9881500..442cca8 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
@@ -17,8 +17,6 @@
 
 package org.apache.isis.core.metamodel.spec.feature;
 
-import static org.apache.isis.core.commons.internal.base._NullSafe.stream;
-
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
@@ -38,6 +36,7 @@ import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.applib.value.Blob;
 import org.apache.isis.applib.value.Clob;
 import org.apache.isis.core.commons.collections.Can;
+import org.apache.isis.core.commons.collections.CanVector;
 import org.apache.isis.core.commons.internal.base._Strings;
 import org.apache.isis.core.commons.internal.collections._Lists;
 import org.apache.isis.core.commons.internal.collections._Sets;
@@ -60,6 +59,8 @@ import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.specimpl.MixedInMember;
 
+import static org.apache.isis.core.commons.internal.base._NullSafe.stream;
+
 import lombok.NonNull;
 import lombok.val;
 
@@ -225,7 +226,7 @@ public interface ObjectAction extends ObjectMember {
      * Returns a list of possible references/values for each parameter, which
      * the user can choose from.
      */
-    Can<Can<ManagedObject>> getChoices(
+    CanVector<ManagedObject> getChoices(
             final ManagedObject target,
             final InteractionInitiatedBy interactionInitiatedBy);
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionDefault.java
index 6e5727d..c4842e4 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionDefault.java
@@ -19,7 +19,6 @@
 
 package org.apache.isis.core.metamodel.specloader.specimpl;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
@@ -33,8 +32,7 @@ import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.applib.services.command.Command;
 import org.apache.isis.applib.services.command.CommandContext;
 import org.apache.isis.core.commons.collections.Can;
-import org.apache.isis.core.commons.exceptions.UnknownTypeException;
-import org.apache.isis.core.commons.internal._Constants;
+import org.apache.isis.core.commons.collections.CanVector;
 import org.apache.isis.core.commons.internal.base._Lazy;
 import org.apache.isis.core.commons.internal.collections._Lists;
 import org.apache.isis.core.metamodel.consent.Consent;
@@ -531,95 +529,82 @@ implements ObjectAction {
     // -- choices
 
     @Override
-    public Can<Can<ManagedObject>> getChoices(
+    public CanVector<ManagedObject> getChoices(
             final ManagedObject target,
             final InteractionInitiatedBy interactionInitiatedBy) {
 
         final int parameterCount = getParameterCount();
-        Object[][] parameterChoicesPojos;
+        CanVector<ManagedObject> paramChoicesVector; 
 
         final ActionChoicesFacet facet = getFacet(ActionChoicesFacet.class);
         val parameters = getParameters();
 
         if (!facet.isFallback()) {
             // using the old choicesXxx() approach
-            parameterChoicesPojos = facet.getChoices(target,
+            paramChoicesVector = facet.getChoices(target,
                     interactionInitiatedBy);
 
             // if no options, or not the right number of pojos, then default
-            if (parameterChoicesPojos == null) {
-                parameterChoicesPojos = new Object[parameterCount][];
-            } else if (parameterChoicesPojos.length != parameterCount) {
+            if (paramChoicesVector == null) {
+                paramChoicesVector = new CanVector<>(parameterCount);
+            } else if (paramChoicesVector.size() != parameterCount) {
                 throw new DomainModelException(
                         String.format("Choices array of incompatible size; expected %d elements, but was %d for %s",
-                                parameterCount, parameterChoicesPojos.length, facet));
+                                parameterCount, paramChoicesVector.size(), facet));
             }
         } else {
             // use the new choicesNXxx approach for each param in turn
             // (the reflector will have made sure both aren't installed).
 
-            parameterChoicesPojos = new Object[parameterCount][];
+            val emptyPendingArgs = Can.<ManagedObject>empty();
+            paramChoicesVector = new CanVector<>(parameterCount);
             for (int i = 0; i < parameterCount; i++) {
-                final ActionParameterChoicesFacet paramFacet = parameters.getElseFail(i).getFacet(ActionParameterChoicesFacet.class);
+                val param = parameters.getElseFail(i);
+                val paramSpec = param.getSpecification();
+                val paramFacet = param.getFacet(ActionParameterChoicesFacet.class);
+                
                 if (paramFacet != null && !paramFacet.isFallback()) {
-                    parameterChoicesPojos[i] = paramFacet.getChoices(target, null,
-                            interactionInitiatedBy);
+                    val visibleChoices = paramFacet.getChoices(paramSpec, target, emptyPendingArgs, interactionInitiatedBy);
+                    ObjectActionParameterAbstract.checkChoicesOrAutoCompleteType(
+                            getSpecificationLoader(), visibleChoices, paramSpec);
+                    paramChoicesVector.set(i, visibleChoices);
                 } else {
-                    parameterChoicesPojos[i] = _Constants.emptyObjects;
+                    paramChoicesVector.set(i, Can.empty());
                 }
             }
         }
-
-        final List<Can<ManagedObject>> parameterChoicesAdapters = new ArrayList<>(parameterCount);
-        for (int i = 0; i < parameterCount; i++) {
-            
-            ManagedObject[] choices;
-            
-            final ObjectSpecification paramSpec = parameters.getElseFail(i).getSpecification();
-
-            if (parameterChoicesPojos[i] != null && parameterChoicesPojos[i].length > 0) {
-                ObjectActionParameterAbstract.checkChoicesOrAutoCompleteType(
-                        getSpecificationLoader(), parameterChoicesPojos[i], paramSpec);
-                choices = new ManagedObject[parameterChoicesPojos[i].length];
-                for (int j = 0; j < parameterChoicesPojos[i].length; j++) {
-                    choices[j] = ManagedObject.of(paramSpec, parameterChoicesPojos[i][j]);
-                }
-            } else if (paramSpec.isNotCollection()) {
-                choices = new ManagedObject[0];
-            } else {
-                throw new UnknownTypeException(paramSpec);
-            }
-
-            if (choices.length == 0) {
-                choices = null;
-            }
-            
-            parameterChoicesAdapters.add(Can.ofArray(choices));
-            
-        }
-
-        return Can.ofCollection(parameterChoicesAdapters);
-    }
-
-
-    //    /**
-    //     * Internal API
-    //     */
-    //    @Override
-    //    public void setupBulkActionInvocationContext(final ObjectAdapter targetAdapter) {
-    //
-    //        final Object targetPojo = ObjectAdapter.Util.unwrap(targetAdapter);
-    //
-    //        final BulkFacet bulkFacet = getFacetHolder().getFacet(BulkFacet.class);
-    //        if (bulkFacet != null) {
-    //            final org.apache.isis.applib.services.actinvoc.ActionInvocationContext actionInvocationContext = getActionInvocationContext();
-    //            if (actionInvocationContext != null && actionInvocationContext.getInvokedOn() == null) {
-    //
-    //                actionInvocationContext.setInvokedOn(InvokedOn.OBJECT);
-    //                actionInvocationContext.setDomainObjects(Collections.singletonList(targetPojo));
-    //            }
-    //        }
-    //    }
+        return paramChoicesVector;
+
+//        final List<Can<ManagedObject>> parameterChoicesAdapters = new ArrayList<>(parameterCount);
+//        for (int i = 0; i < parameterCount; i++) {
+//            
+//            ManagedObject[] choices;
+//            
+//            final ObjectSpecification paramSpec = parameters.getElseFail(i).getSpecification();
+//
+//            if (paramChoicesVector[i] != null && paramChoicesVector[i].length > 0) {
+//                ObjectActionParameterAbstract.checkChoicesOrAutoCompleteType(
+//                        getSpecificationLoader(), paramChoicesVector[i], paramSpec);
+//                choices = new ManagedObject[paramChoicesVector[i].length];
+//                for (int j = 0; j < paramChoicesVector[i].length; j++) {
+//                    choices[j] = ManagedObject.of(paramSpec, paramChoicesVector[i][j]);
+//                }
+//            } else if (paramSpec.isNotCollection()) {
+//                choices = new ManagedObject[0];
+//            } else {
+//                throw new UnknownTypeException(paramSpec);
+//            }
+//
+//            if (choices.length == 0) {
+//                choices = null;
+//            }
+//            
+//            parameterChoicesAdapters.add(Can.ofArray(choices));
+//            
+//        }
+//
+//        return Can.ofCollection(parameterChoicesAdapters);
+    }
 
     @Override
     public boolean isPrototype() {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
index be912e9..3fb4d5d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
@@ -22,6 +22,7 @@ import java.util.List;
 
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.core.commons.collections.Can;
+import org.apache.isis.core.commons.collections.CanVector;
 import org.apache.isis.core.commons.internal.assertions._Assert;
 import org.apache.isis.core.commons.internal.base._Strings;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
@@ -140,7 +141,7 @@ public class ObjectActionMixedIn extends ObjectActionDefault implements MixedInM
     }
 
     @Override
-    public Can<Can<ManagedObject>> getChoices(
+    public CanVector<ManagedObject> getChoices(
             final ManagedObject mixedInAdapter,
             final InteractionInitiatedBy interactionInitiatedBy) {
         final ManagedObject mixinAdapter = mixinAdapterFor(mixedInAdapter);
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionParameterAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionParameterAbstract.java
index 79ea71c..eedddcd 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionParameterAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionParameterAbstract.java
@@ -20,11 +20,9 @@
 package org.apache.isis.core.metamodel.specloader.specimpl;
 
 import java.util.ArrayList;
-import java.util.List;
 
 import org.apache.isis.applib.Identifier;
 import org.apache.isis.core.commons.collections.Can;
-import org.apache.isis.core.commons.internal.collections._Lists;
 import org.apache.isis.core.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.metamodel.commons.ClassExtensions;
 import org.apache.isis.core.metamodel.commons.StringExtensions;
@@ -187,18 +185,16 @@ implements ObjectActionParameter, FacetHolder.Delegating {
             final String searchArg,
             final InteractionInitiatedBy interactionInitiatedBy) {
 
-        val adapters = _Lists.<ManagedObject>newArrayList();
         val autoCompleteFacet = getFacet(ActionParameterAutoCompleteFacet.class);
-
-        if (autoCompleteFacet != null) {
-            final Object[] choices = autoCompleteFacet
-                    .autoComplete(pendingArgs.getActionTarget(), pendingArgs.getParamValues(), searchArg, interactionInitiatedBy);
-            checkChoicesOrAutoCompleteType(getSpecificationLoader(), choices, getSpecification());
-            for (final Object choice : choices) {
-                adapters.add(getObjectManager().adapt(choice));
-            }
+        if (autoCompleteFacet == null) {
+            return Can.empty();
         }
-        return Can.ofCollection(adapters);
+        
+        val visibleChoices = autoCompleteFacet
+                .autoComplete(pendingArgs.getActionTarget(), pendingArgs.getParamValues(), searchArg, interactionInitiatedBy);
+        checkChoicesOrAutoCompleteType(getSpecificationLoader(), visibleChoices, getSpecification());
+        
+        return visibleChoices;
     }
 
     @Override
@@ -208,12 +204,11 @@ implements ObjectActionParameter, FacetHolder.Delegating {
     }
 
 
-
     // -- Choices
 
     @Override
     public boolean hasChoices() {
-        final ActionParameterChoicesFacet choicesFacet = getFacet(ActionParameterChoicesFacet.class);
+        val choicesFacet = getFacet(ActionParameterChoicesFacet.class);
         return choicesFacet != null;
     }
 
@@ -221,26 +216,17 @@ implements ObjectActionParameter, FacetHolder.Delegating {
     public Can<ManagedObject> getChoices(
             final PendingParameterModel pendingArgs,
             final InteractionInitiatedBy interactionInitiatedBy) {
-        
-        return findChoices(pendingArgs, interactionInitiatedBy);
-    }
 
-    private Can<ManagedObject> findChoices(
-            final PendingParameterModel pendingArgs,
-            final InteractionInitiatedBy interactionInitiatedBy) {
-        
-        final List<ManagedObject> adapters = _Lists.newArrayList();
-        final ActionParameterChoicesFacet facet = getFacet(ActionParameterChoicesFacet.class);
-
-        if (facet != null) {
-            final Object[] choices = facet.getChoices(pendingArgs.getActionTarget(), pendingArgs.getParamValues(), interactionInitiatedBy);
-            checkChoicesOrAutoCompleteType(getSpecificationLoader(), choices, getSpecification());
-            for (final Object choice : choices) {
-                ManagedObject adapter = choice != null? getObjectManager().adapt(choice) : null;
-                adapters.add(adapter);
-            }
+        val paramSpec = getSpecification();        
+        val choicesFacet = getFacet(ActionParameterChoicesFacet.class);
+        if (choicesFacet == null) {
+            return Can.empty();
         }
-        return Can.ofCollection(adapters);
+
+        val visibleChoices = choicesFacet.getChoices(paramSpec, pendingArgs.getActionTarget(), pendingArgs.getParamValues(), interactionInitiatedBy);
+        checkChoicesOrAutoCompleteType(getSpecificationLoader(), visibleChoices, getSpecification());
+        
+        return visibleChoices;
     }
 
     // -- Defaults
@@ -262,17 +248,20 @@ implements ObjectActionParameter, FacetHolder.Delegating {
     // helpers
     static void checkChoicesOrAutoCompleteType(
             final SpecificationLoader specificationLookup,
-            final Object[] objects,
+            final Can<ManagedObject> choices,
             final ObjectSpecification paramSpec) {
-        for (final Object object : objects) {
+        
+        for (final ManagedObject choice : choices) {
+            
+            val choicePojo = choice.getPojo();
 
-            if(object == null) {
+            if(choicePojo == null) {
                 continue;
             }
 
             // check type, but wrap first
             // (eg we treat int.class and java.lang.Integer.class as compatible with each other)
-            final Class<?> choiceClass = object.getClass();
+            final Class<?> choiceClass = choicePojo.getClass();
             final Class<?> paramClass = paramSpec.getCorrespondingClass();
 
             final Class<?> choiceWrappedClass = ClassExtensions.asWrappedIfNecessary(choiceClass);
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationDefault.java
index e33928c..56c1b8c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationDefault.java
@@ -254,17 +254,12 @@ implements OneToOneAssociation {
 
         val propertyChoicesFacet = getFacet(PropertyChoicesFacet.class);
         if (propertyChoicesFacet == null) {
-            return null;
+            return Can.empty();
         }
 
-        final Object[] pojoOptions = propertyChoicesFacet.getChoices(
+        return propertyChoicesFacet.getChoices(
                 ownerAdapter,
                 interactionInitiatedBy);
-
-        val adapters = _NullSafe.stream(pojoOptions)
-                .map(getObjectManager()::adapt)
-                .collect(Can.toCan());
-        return adapters;
     }
 
 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/reference/ReferencePanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/reference/ReferencePanel.java
index cea4d1f..7751035 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/reference/ReferencePanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/reference/ReferencePanel.java
@@ -340,7 +340,7 @@ public class ReferencePanel extends ScalarPanelSelectAbstract {
         val scalarModel = getModel();
         
         if (scalarModel.hasChoices()) {
-            val choices = scalarModel.getChoices();
+            val choices = scalarModel.getChoices(); //FIXME must not return detached entities
             val choiceMementos = choices.map(commonContext::mementoForParameter);
             return new ObjectAdapterMementoProviderForReferenceChoices(scalarModel, choiceMementos);
         }
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 b0178da..74cff48 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
@@ -33,6 +33,7 @@ import org.springframework.stereotype.Service;
 import org.apache.isis.applib.annotation.OrderPrecedence;
 import org.apache.isis.applib.services.bookmark.Bookmark;
 import org.apache.isis.core.commons.internal.base._NullSafe;
+import org.apache.isis.core.commons.internal.debug._Probe;
 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;
@@ -67,15 +68,18 @@ public class ObjectMementoServiceWicket implements ObjectMementoService {
 
     @Override
     public ObjectMemento mementoForRootOid(@NonNull RootOid rootOid) {
+        _Probe.errOut("mementoForRootOid %s", rootOid);
         val mementoAdapter = ObjectMementoLegacy.createPersistent(rootOid, specificationLoader);
         return ObjectMementoAdapter.of(mementoAdapter);
     }
 
     @Override
     public ObjectMemento mementoForObject(@Nullable ManagedObject adapter) {
+        assertSingleton(adapter);
+        _Probe.errOut("mementoForObject %s", adapter);
         val mementoAdapter = ObjectMementoLegacy.createOrNull(adapter);
         if(mementoAdapter==null) {
-            // sonar-ignore-on (fails to detect this as null guard) 
+            // sonar-ignore-on (fails to detect this as null guard)
             return ManagedObjects.isSpecified(adapter)
                     ? new ObjectMementoForEmpty(adapter.getSpecification().getSpecId())
                     : null;
@@ -86,6 +90,8 @@ public class ObjectMementoServiceWicket implements ObjectMementoService {
     
     @Override
     public ObjectMemento mementoForParameter(@NonNull ManagedObject paramAdapter) {
+        _Probe.errOut("mementoForParameter %s", paramAdapter);
+        assertSingleton(paramAdapter);
         val mementoAdapter = ObjectMementoLegacy.createOrNull(paramAdapter);
         if(mementoAdapter==null) {
             return new ObjectMementoForEmpty(paramAdapter.getSpecification().getSpecId());
@@ -96,12 +102,16 @@ public class ObjectMementoServiceWicket implements ObjectMementoService {
 
     @Override
     public ObjectMemento mementoForPojo(Object pojo) {
+        _Probe.errOut("mementoForPojo %s", ""+pojo);
+        assertSingleton(pojo);
+        
         val managedObject = objectManager.adapt(pojo);
         return mementoForObject(managedObject);
     }
     
     @Override
     public ObjectMemento mementoForPojos(Iterable<Object> iterablePojos, ObjectSpecId specId) {
+        _Probe.errOut("mementoForPojos");
         val listOfMementos = _NullSafe.stream(iterablePojos)
                 .map(pojo->mementoForPojo(pojo))
                 .collect(Collectors.toCollection(ArrayList::new)); // ArrayList is serializable
@@ -143,6 +153,25 @@ public class ObjectMementoServiceWicket implements ObjectMementoService {
 
         throw _Exceptions.unrecoverableFormatted("unsupported ObjectMemento type %s", memento.getClass());
     }
+    
+    private void assertSingleton(ManagedObject adapter) {
+        if(ManagedObjects.isNullOrUnspecifiedOrEmpty(adapter)) {
+            return;
+        }
+        val pojo = ManagedObjects.UnwrapUtil.single(adapter);
+        assertSingleton(pojo);
+        val spec = adapter.getSpecification();
+        if(!spec.isNotCollection()) {
+            throw _Exceptions.illegalArgument("unexpected spec type %s for %s (elementSpec=%s)", 
+                    spec, spec.getFullIdentifier(), spec.getElementSpecification());
+        }
+    }
+    
+    private void assertSingleton(Object pojo) {
+        if(_NullSafe.streamAutodetect(pojo).limit(2).count()>1L) {
+            throw _Exceptions.illegalArgument("cardinality 0 or 1 expect");
+        }
+    }
 
     @RequiredArgsConstructor(staticName = "of")
     private static class ObjectMementoAdapter implements ObjectMemento {