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 2019/10/28 17:16:16 UTC

[isis] 04/10: ISIS-2158: properly implement MultiTypedFacet replacements concept

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

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

commit 3e4ca1bb7db706f4e015e4ec29d4288a3a9a1c98
Author: Andi Huber <ah...@apache.org>
AuthorDate: Mon Oct 28 09:32:12 2019 +0100

    ISIS-2158: properly implement MultiTypedFacet replacements concept
---
 .../applib/services/registry/ServiceRegistry.java  |   6 +-
 .../commons/collections/{Bin.java => Can.java}     | 155 ++++++++++++---------
 .../collections/{Bin_Empty.java => Can_Empty.java} |   8 +-
 .../{Bin_Multiple.java => Can_Multiple.java}       |   2 +-
 .../{Bin_Singleton.java => Can_Singleton.java}     |   2 +-
 .../isis/commons/internal/collections/_Lists.java  |  18 +--
 .../isis/commons/internal/collections/_Maps.java   | 145 +++++++++++++++++++
 .../commons/internal/collections/_Multimaps.java   |   5 +-
 .../isis/commons/internal/collections/_Sets.java   |   1 -
 .../isis/commons/internal/context/_Context.java    |   6 +-
 .../internal/context/_Context_ThreadLocal.java     |  22 +--
 .../isis/commons/internal/ioc/IocContainer.java    |   6 +-
 .../commons/internal/ioc/ManagedBeanAdapter.java   |   4 +-
 .../commons/internal/ioc/cdi/BeanAdapterCDI.java   |   4 +-
 .../apache/isis/commons/internal/ioc/cdi/_CDI.java |  14 +-
 .../internal/ioc/spring/BeanAdapterSpring.java     |   6 +-
 .../internal/ioc/spring/IocContainerSpring.java    |  12 +-
 .../commons/internal/collections/_MapsTest.java    | 127 +++++++++++++++++
 .../loader/ObjectLoader_builtinHandlers.java       |   4 +-
 .../isis/metamodel/consent/InteractionAdvisor.java |  12 +-
 .../org/apache/isis/metamodel/facetapi/Facet.java  |  16 ++-
 .../isis/metamodel/facetapi/FacetAbstract.java     |  37 +++--
 .../isis/metamodel/facetapi/FacetHolder.java       |  13 +-
 .../isis/metamodel/facetapi/FacetHolderImpl.java   | 144 +++++++++++--------
 .../isis/metamodel/facetapi/MetaModelRefiner.java  |   4 +-
 ...nChoicesForCollectionParameterFacetFactory.java |   2 +-
 .../actions/layout/ActionLayoutFacetFactory.java   |   2 +-
 .../PromptStyleFacetForActionLayoutAnnotation.java |   4 +-
 .../facets/all/deficiencies/DeficiencyFacet.java   |   8 +-
 ...cetOnCollectionDerivedFromImmutableFactory.java |   2 +-
 .../metamodel/facets/jaxb/JaxbFacetFactory.java    |   2 +-
 ...assFacetOnActionFromConfiguredRegexFactory.java |   4 +-
 .../facets/members/hidden/HiddenFacetAbstract.java |  12 +-
 .../ImmutableFacetForDomainObjectAnnotation.java   |   2 +-
 .../facets/object/entity/EntityFacet.java          |   2 -
 ...jectSpecIdFacetDerivedFromClassNameFactory.java |   2 +-
 ...CollectionDerivedFromViewModelFacetFactory.java |   2 +-
 ...tyDerivedFromRecreatableObjectFacetFactory.java |   2 +-
 ...ObjectFacetDeclarativeInitializingAbstract.java |   2 +-
 .../facets/object/value/ValueFacetAbstract.java    |  11 +-
 .../facets/object/value/ValueFacetSimple.java      |   1 +
 ...ChoicesFacetDerivedFromChoicesFacetFactory.java |   4 +-
 ...ctionParameterChoicesFacetViaMethodFactory.java |   2 +-
 ...tionParameterDefaultsFacetViaMethodFactory.java |   2 +-
 ...ChoicesFacetDerivedFromChoicesFacetFactory.java |   2 +-
 ...FacetOnPropertyDerivedFromImmutableFactory.java |   2 +-
 .../DisabledFacetOnPropertyInferredFactory.java    |   4 +-
 ...romptStyleFacetForPropertyLayoutAnnotation.java |   4 +-
 .../param/DeriveFacetsPostProcessor.java           |  32 ++---
 .../ApplicationFeatureRepositoryDefault.java       |   4 +-
 .../services/registry/ServiceRegistryDefault.java  |   4 +-
 .../metamodel/spec/feature/ObjectAssociation.java  |   2 +-
 .../specloader/SpecificationCacheDefault.java      |   2 +-
 .../isis/metamodel/ServiceRegistry_forTesting.java |  14 +-
 .../Annotations_getAnnotations_on_Field_Test.java  |   4 -
 ...notations_getAnnotations_on_Parameter_Test.java |   4 -
 ...nnotationFacetFactoryTest_ActionInvocation.java |   1 -
 ...ctionAnnotationFacetFactoryTest_Invocation.java |   1 -
 ...eFacetAnnotationOrConfigurationFactoryTest.java |   3 -
 ...romptStyleFacetFromPropertyAnnotation_Test.java |   8 +-
 .../specimpl/ObjectAssociationAbstractTest.java    |   2 +-
 ...ObjectAssociationAbstractTest_alwaysHidden.java |   2 +-
 .../jdo/metamodel/JdoProgrammingModelPlugin.java   |   2 +-
 .../JdoPersistenceCapableFacetAbstract.java        |   2 +-
 ...DerivedFromJdoColumnAnnotationFacetFactory.java |   2 +-
 ...ndatoryFromJdoColumnAnnotationFacetFactory.java |   2 +-
 ...DerivedFromJdoColumnAnnotationFacetFactory.java |   2 +-
 .../homepage/HomePageResolverServiceDefault.java   |   2 +-
 .../isis/runtime/services/i18n/po/PoReader.java    |   6 +-
 .../services/i18n/po/TranslationServicePo.java     |  10 +-
 .../runtime/services/i18n/po/PoReaderTest.java     |   6 +-
 .../system/persistence/PersistenceSession.java     |   4 +-
 .../wicket/model/models/EntityCollectionModel.java |   5 +-
 .../model/models/ToggledMementosProvider.java      |   5 +-
 .../actionmenu/entityactions/LinkAndLabelUtil.java |   9 +-
 .../ui/components/collection/CollectionPanel.java  |   3 +-
 .../CollectionContentsAsAjaxTablePanel.java        |   4 +-
 .../CollectionContentsAsSummaryFactory.java        |   2 +-
 .../wicket/ui/components/layout/bs3/col/Col.java   |   8 +-
 .../linkandlabel/ActionLinkFactoryAbstract.java    |  21 ++-
 .../wicket/ui/pages/login/IsisSignInPanel.java     |   6 +-
 .../fixturespec/FixtureScriptsDefault.java         |   4 +-
 82 files changed, 682 insertions(+), 359 deletions(-)

diff --git a/core/applib/src/main/java/org/apache/isis/applib/services/registry/ServiceRegistry.java b/core/applib/src/main/java/org/apache/isis/applib/services/registry/ServiceRegistry.java
index 77d8a2c..f319546 100644
--- a/core/applib/src/main/java/org/apache/isis/applib/services/registry/ServiceRegistry.java
+++ b/core/applib/src/main/java/org/apache/isis/applib/services/registry/ServiceRegistry.java
@@ -27,7 +27,7 @@ import java.util.stream.Stream;
 
 import javax.annotation.Priority;
 
-import org.apache.isis.commons.collections.Bin;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal._Constants;
 import org.apache.isis.commons.internal.base._Reduction;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
@@ -52,7 +52,7 @@ public interface ServiceRegistry {
      * @return non-null
      * 
      */
-    public <T> Bin<T> select(Class<T> type, Annotation[] qualifiers);
+    public <T> Can<T> select(Class<T> type, Annotation[] qualifiers);
 
     /**
      * Obtains a Bin container containing any matching instances for the given required type. 
@@ -60,7 +60,7 @@ public interface ServiceRegistry {
      * @return non-null
      * 
      */
-    default public <T> Bin<T> select(final Class<T> type){
+    default public <T> Can<T> select(final Class<T> type){
         return select(type, _Constants.emptyAnnotations);
     }
 
diff --git a/core/commons/src/main/java/org/apache/isis/commons/collections/Bin.java b/core/commons/src/main/java/org/apache/isis/commons/collections/Can.java
similarity index 63%
rename from core/commons/src/main/java/org/apache/isis/commons/collections/Bin.java
rename to core/commons/src/main/java/org/apache/isis/commons/collections/Can.java
index 6e68451..be7af92 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/collections/Bin.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/collections/Can.java
@@ -31,8 +31,6 @@ import java.util.stream.Stream;
 import javax.annotation.Nullable;
 import javax.enterprise.inject.Instance;
 
-import org.springframework.core.annotation.AnnotationAwareOrderComparator;
-
 import org.apache.isis.commons.internal.base._NullSafe;
 
 import static org.apache.isis.commons.internal.base._With.requires;
@@ -41,88 +39,125 @@ import lombok.val;
 
 /**
  * 
- * Immutable 'multi-set', that is particularly designed to conveniently deal 
- * with the 3 possible states of {@link Cardinality}. 
+ * Immutable {@link Iterable}, that can specifically represent 3 possible variants of 
+ * {@link Cardinality}. 
+ * <p>
+ * Java's {@link Optional}, can be seen as a holder of element(s), that is restricted to 
+ * cardinality ZERO or ONE. {@link Can} is the logical extension to that, allowing also a 
+ * cardinality of MULTIPLE.
+ * <p> 
+ * Same idiomatic convention applies: References to {@link Can} 
+ * should never be initialized to {@code null}.
  * <p>
- * A {@code Bin} must not contain elements equal to {@code null}.
+ * A {@link Can} must not contain elements equal to {@code null}.
  * 
  * @param <T>
  * @since 2.0
  */
-public interface Bin<T> extends Iterable<T> {
+public interface Can<T> extends Iterable<T> {
 
     /**
-     * @return this Bin's cardinality
+     * @return this Can's cardinality
      */
     Cardinality getCardinality();
-    
+
     /**
-     * @return number of elements this Bin contains 
+     * @return number of elements this Can contains 
      */
     int size();
 
     /**
-     * @return Stream of elements this Bin contains
+     * @return Stream of elements this Can contains
      */
     Stream<T> stream();
 
     /**
-     * @return this Bin's first element or an empty Optional if no such element
+     * @return this Can's first element or an empty Optional if no such element
      */
     Optional<T> getFirst();
-    
+
     /**
-     * @return this Bin's single element or an empty Optional if this Bin has any cardinality other than ONE 
+     * @return this Can's single element or an empty Optional if this Can has any cardinality other than ONE 
      */
     Optional<T> getSingleton();
 
     // -- FACTORIES
 
     /**
-     * Returns an empty {@code Bin}.
+     * Returns an empty {@code Can}.
      * @param <T>
      */
     @SuppressWarnings("unchecked") // this is how the JDK does it for eg. empty lists
-    public static <T> Bin<T> empty() {
-        return (Bin<T>) Bin_Empty.INSTANCE;
+    public static <T> Can<T> empty() {
+        return (Can<T>) Can_Empty.INSTANCE;
     }
 
     /**
-     * Returns either a {@code Bin} with the given {@code element} or an empty {@code Bin} if the
+     * Returns either a {@code Can} with the given {@code element} or an empty {@code Can} if the
      * {@code element} is {@code null}.
      * @param <T>
      * @param element
      * @return non-null
      */
-    public static <T> Bin<T> ofNullable(@Nullable T element) {
+    public static <T> Can<T> ofNullable(@Nullable T element) {
         if(element==null) {
             return empty();
         }
-        return Bin_Singleton.of(element);
+        return Can_Singleton.of(element);
     }
 
     /**
-     * Returns either a {@code Bin} with the given {@code element} or throws if the
+     * Returns either a {@code Can} with the given {@code element} or throws if the
      * {@code element} is {@code null}.
      * @param <T>
      * @param element
      * @return non-null
      * @throws NullPointerException if {@code element} is {@code null}
      */
-    public static <T> Bin<T> ofSingleton(T element) {
+    public static <T> Can<T> ofSingleton(T element) {
         requires(element, "element");
-        return Bin_Singleton.of(element);
+        return Can_Singleton.of(element);
+    }
+
+    public static <T> Can<T> ofArray(@Nullable T[] array) {
+
+        if(_NullSafe.size(array)==0) {
+            return empty();
+        }
+
+        // this is just an optimization, to pre-allocate a reasonable list size,
+        // specifically targeted at small list sizes
+        val maxSize = Math.min(array.length, 1024);
+        
+        val nonNullElements = Stream.of(array)
+                .filter(_NullSafe::isPresent)
+                .collect(Collectors.toCollection(()->new ArrayList<>(maxSize)));
+
+        nonNullElements.trimToSize(); // in case we have a 'sparse' collection as input to this method
+
+        val size = nonNullElements.size();
+
+        if(size==0) {
+            return empty();
+        }
+
+        if(size==1) {
+            return ofSingleton(((List<T>)nonNullElements).get(0));
+        }
+
+        return Can_Multiple.of(nonNullElements);
+
     }
 
     /**
-     * Returns either a {@code Bin} with all the elements from given {@code collection} 
-     * or an empty {@code Bin} if the {@code collection} is {@code null}. Any elements
-     * equal to {@code null} are ignored and will not be contained in the resulting {@code Bin}.
+     * Returns either a {@code Can} with all the elements from given {@code collection} 
+     * or an empty {@code Can} if the {@code collection} is {@code null}. Any elements
+     * equal to {@code null} are ignored and will not be contained in the resulting {@code Can}.
      * @param <T>
      * @param collection
      * @return non-null
      */
-    public static <T> Bin<T> ofCollection(@Nullable Collection<T> collection) {
+    public static <T> Can<T> ofCollection(@Nullable Collection<T> collection) {
 
         if(_NullSafe.size(collection)==0) {
             return empty();
@@ -148,20 +183,18 @@ public interface Bin<T> extends Iterable<T> {
             return ofSingleton(((List<T>)nonNullElements).get(0));
         }
 
-        nonNullElements.sort(AnnotationAwareOrderComparator.INSTANCE);
-
-        return Bin_Multiple.of(nonNullElements);
+        return Can_Multiple.of(nonNullElements);
     }
 
     /**
-     * Returns either a {@code Bin} with all the elements from given {@code stream} 
-     * or an empty {@code Bin} if the {@code stream} is {@code null}. Any elements
-     * equal to {@code null} are ignored and will not be contained in the resulting {@code Bin}.
+     * Returns either a {@code Can} with all the elements from given {@code stream} 
+     * or an empty {@code Can} if the {@code stream} is {@code null}. Any elements
+     * equal to {@code null} are ignored and will not be contained in the resulting {@code Can}.
      * @param <T>
      * @param stream
      * @return non-null
      */
-    public static <T> Bin<T> ofStream(@Nullable Stream<T> stream) {
+    public static <T> Can<T> ofStream(@Nullable Stream<T> stream) {
 
         if(stream==null) {
             return empty();
@@ -181,32 +214,28 @@ public interface Bin<T> extends Iterable<T> {
             return ofSingleton(((List<T>)nonNullElements).get(0));
         }
 
-        nonNullElements.sort(AnnotationAwareOrderComparator.INSTANCE);
-
-        return Bin_Multiple.of(nonNullElements);
+        return Can_Multiple.of(nonNullElements);
     }
 
     /**
-     * Returns either a {@code Bin} with all the elements from given {@code instance} 
-     * or an empty {@code Bin} if the {@code instance} is {@code null}. Any elements
-     * equal to {@code null} are ignored and will not be contained in the resulting {@code Bin}.
+     * Returns either a {@code Can} with all the elements from given {@code instance} 
+     * or an empty {@code Can} if the {@code instance} is {@code null}. Any elements
+     * equal to {@code null} are ignored and will not be contained in the resulting {@code Can}.
      * @param <T>
      * @param instance
      * @return non-null
      */
-    public static <T> Bin<T> ofInstance(@Nullable Instance<T> instance) {
+    public static <T> Can<T> ofInstance(@Nullable Instance<T> instance) {
         if(instance==null || instance.isUnsatisfied()) {
             return empty();
         }
         if(instance.isResolvable()) { 
-            return Bin_Singleton.of(instance.get());
+            return Can_Singleton.of(instance.get());
         }
         val nonNullElements = instance.stream()
                 .collect(Collectors.toCollection(()->new ArrayList<>()));
 
-        nonNullElements.sort(AnnotationAwareOrderComparator.INSTANCE);
-
-        return Bin_Multiple.of(nonNullElements);
+        return Can_Multiple.of(nonNullElements);
 
     }
 
@@ -214,13 +243,13 @@ public interface Bin<T> extends Iterable<T> {
     // -- OPERATORS
 
     /**
-     * Returns a {@code Bin} with all the elements from this {@code Bin},
+     * Returns a {@code Can} with all the elements from this {@code Can},
      * that are accepted by the given {@code predicate}. If {@code predicate}
      * is {@code null} <em>all</em> elements are accepted.
      * @param predicate - if absent accepts all
      * @return non-null
      */
-    public default Bin<T> filter(@Nullable Predicate<? super T> predicate) {
+    public default Can<T> filter(@Nullable Predicate<? super T> predicate) {
         if(predicate==null || isEmpty()) {
             return this;
         }
@@ -247,15 +276,15 @@ public interface Bin<T> extends Iterable<T> {
     }
 
     /**
-     * Returns a {@code Bin} with all the elements from this {@code Bin}
+     * Returns a {@code Can} with all the elements from this {@code Can}
      * 'transformed' by the given {@code mapper} function. Any resulting elements
-     * equal to {@code null} are ignored and will not be contained in the resulting {@code Bin}.
+     * equal to {@code null} are ignored and will not be contained in the resulting {@code Can}.
      * 
      * @param <R>
-     * @param mapper - if absent throws if this {@code Bin} is non-empty 
+     * @param mapper - if absent throws if this {@code Can} is non-empty 
      * @return non-null
      */
-    default <R> Bin<R> map(Function<? super T, R> mapper) {
+    default <R> Can<R> map(Function<? super T, R> mapper) {
 
         if(isEmpty()) {
             return empty();
@@ -271,32 +300,32 @@ public interface Bin<T> extends Iterable<T> {
 
         return ofCollection(mappedElements);
     }
-    
+
     // -- CONCATENATION
 
     /**
-     * Returns a {@code Bin} with all the elements from given {@code bin} joined by 
-     * the given {@code element}. If any of given {@code bin} or {@code element} are {@code null}
+     * Returns a {@code Can} with all the elements from given {@code can} joined by 
+     * the given {@code element}. If any of given {@code can} or {@code element} are {@code null}
      * these do not contribute any elements and are ignored.
      * @param <T>
-     * @param bin - nullable
+     * @param can - nullable
      * @param element - nullable
      * @return non-null
      */
-    public static <T> Bin<T> concat(@Nullable Bin<T> bin, @Nullable T element) {
-        if(bin==null || bin.isEmpty()) {
+    public static <T> Can<T> concat(@Nullable Can<T> can, @Nullable T element) {
+        if(can==null || can.isEmpty()) {
             return ofNullable(element);
         }
         if(element==null) {
-            return bin;
+            return can;
         }
-        // at this point: bin is not empty and variant is not null
-        val newSize = bin.size() + 1;
-        val union = bin.stream().collect(Collectors.toCollection(()->new ArrayList<>(newSize)));
+        // at this point: can is not empty and variant is not null
+        val newSize = can.size() + 1;
+        val union = can.stream().collect(Collectors.toCollection(()->new ArrayList<>(newSize)));
         union.add(element);
-        return Bin_Multiple.of(union);
+        return Can_Multiple.of(union);
     }
-    
+
     // -- TRAVERSAL
 
     @Override
@@ -324,4 +353,6 @@ public interface Bin<T> extends Iterable<T> {
     }
 
 
+
+
 }
diff --git a/core/commons/src/main/java/org/apache/isis/commons/collections/Bin_Empty.java b/core/commons/src/main/java/org/apache/isis/commons/collections/Can_Empty.java
similarity index 87%
rename from core/commons/src/main/java/org/apache/isis/commons/collections/Bin_Empty.java
rename to core/commons/src/main/java/org/apache/isis/commons/collections/Can_Empty.java
index bf57f45..9520450 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/collections/Bin_Empty.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/collections/Can_Empty.java
@@ -23,12 +23,14 @@ import java.util.Iterator;
 import java.util.Optional;
 import java.util.stream.Stream;
 
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
 import lombok.Value;
 
-@Value(staticConstructor="of")
-final class Bin_Empty<T> implements Bin<T> {
+@Value @NoArgsConstructor(access = AccessLevel.PRIVATE)
+final class Can_Empty<T> implements Can<T> {
 
-    static final Bin_Empty<?> INSTANCE = new Bin_Empty<>(); 
+    static final Can_Empty<?> INSTANCE = new Can_Empty<>(); 
 
     @Override
     public Cardinality getCardinality() {
diff --git a/core/commons/src/main/java/org/apache/isis/commons/collections/Bin_Multiple.java b/core/commons/src/main/java/org/apache/isis/commons/collections/Can_Multiple.java
similarity index 97%
rename from core/commons/src/main/java/org/apache/isis/commons/collections/Bin_Multiple.java
rename to core/commons/src/main/java/org/apache/isis/commons/collections/Can_Multiple.java
index 2492689..e2dabba 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/collections/Bin_Multiple.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/collections/Can_Multiple.java
@@ -30,7 +30,7 @@ import lombok.RequiredArgsConstructor;
 import lombok.val;
 
 @RequiredArgsConstructor(staticName="of")
-final class Bin_Multiple<T> implements Bin<T> {
+final class Can_Multiple<T> implements Can<T> {
 
     private final List<T> elements;
 
diff --git a/core/commons/src/main/java/org/apache/isis/commons/collections/Bin_Singleton.java b/core/commons/src/main/java/org/apache/isis/commons/collections/Can_Singleton.java
similarity index 97%
rename from core/commons/src/main/java/org/apache/isis/commons/collections/Bin_Singleton.java
rename to core/commons/src/main/java/org/apache/isis/commons/collections/Can_Singleton.java
index a0b196a..ec82764 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/collections/Bin_Singleton.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/collections/Can_Singleton.java
@@ -27,7 +27,7 @@ import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 
 @RequiredArgsConstructor(staticName="of")
-final class Bin_Singleton<T> implements Bin<T> {
+final class Can_Singleton<T> implements Can<T> {
 
     private final T element;
 
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Lists.java b/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Lists.java
index 985385b..1f40c04 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Lists.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Lists.java
@@ -29,7 +29,6 @@ import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 import javax.annotation.Nullable;
 
@@ -169,21 +168,16 @@ public final class _Lists {
 
     // -- TRANSFORMATIONS
 
-    public static <T, R> List<R> transform(@Nullable Collection<T> input, Function<Stream<T>, Stream<R>> transformation) {
-        if(input==null) {
-            return Collections.emptyList();
-        }
-        requires(transformation, "transformation");
-        return transformation.apply(_NullSafe.stream(input))
-                .collect(Collectors.toList());
-    }
-
     public static <T, R> List<R> map(@Nullable Collection<T> input, Function<T, R> mapper) {
-        return transform(input, stream->stream.map(mapper));
+        return _NullSafe.stream(input)
+                .map(mapper)
+                .collect(Collectors.toList());
     }
 
     public static <T> List<T> filter(@Nullable Collection<T> input, Predicate<? super T> filter) {
-        return transform(input, stream->stream.filter(filter));
+        return _NullSafe.stream(input)
+                .filter(filter)
+                .collect(Collectors.toList());
     }
 
 }
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Maps.java b/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Maps.java
index f18fc78..ec032df 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Maps.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Maps.java
@@ -20,11 +20,13 @@
 package org.apache.isis.commons.internal.collections;
 
 import java.util.AbstractMap;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
+import java.util.Set;
 import java.util.TreeMap;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Predicate;
@@ -33,10 +35,16 @@ import java.util.stream.Stream;
 
 import javax.annotation.Nullable;
 
+import org.apache.isis.commons.collections.Can;
+import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.collections._Multimaps.ListMultimap;
+import org.apache.isis.commons.internal.exceptions._Exceptions;
 
 import static org.apache.isis.commons.internal.base._With.requires;
 
+import lombok.Value;
+import lombok.val;
+
 /**
  * <h1>- internal use only -</h1>
  * <p>
@@ -52,6 +60,27 @@ import static org.apache.isis.commons.internal.base._With.requires;
 public final class _Maps {
 
     private _Maps(){}
+    
+    /**
+     * A Map that supports value lookup by key and <em>alias</em> keys.
+     * <p>
+     * example use-case: store values by class type then allow lookup by interface type
+     * @param <K>
+     * @param <V>
+     */
+    public static interface AliasMap<K, V> extends Map<K, V> {
+
+        /**
+         * 
+         * @param key
+         * @param aliases
+         * @param value
+         * @return
+         * @throws IllegalArgumentException if there is a aliasKey collision
+         */
+        public V put(K key, Can<K> aliases, V value);
+        
+    }
 
     // -- UNMODIFIABLE MAP
 
@@ -165,6 +194,122 @@ public final class _Maps {
     public static <K, V> TreeMap<K, V> newTreeMap(Comparator<? super K> comparator) {
         return new TreeMap<K, V>(comparator);
     }
+    
+    // -- ALIAS MAP
+    
+    @Value(staticConstructor = "of") 
+    private final static class KeyPair<K> {
+        K key;
+        Can<K> aliasKeys;
+    }
+    
+    public static <K, V> AliasMap<K, V> newAliasMap(
+            final Supplier<Map<K, V>> mapFactory){
+        
+        requires(mapFactory, "mapFactory");
+
+        return new AliasMap<K, V>() {
+
+            final Map<K, V> delegate = mapFactory.get();
+
+            @Override public int size() { return delegate.size(); }
+            @Override public boolean isEmpty() { return delegate.isEmpty(); }
+            @Override public boolean containsValue(Object value) { return delegate.containsValue(value); }
+            @Override public Set<K> keySet() { return delegate.keySet(); }
+            @Override public Collection<V> values() { return delegate.values();   }
+            @Override public Set<Entry<K, V>> entrySet() { return delegate.entrySet(); }
+            
+            @Override 
+            public V put(K key, V value) { 
+                return this.put(key, Can.empty(), value); 
+            }
+            
+            @Override 
+            public void putAll(Map<? extends K, ? extends V> other) { 
+                if(!_NullSafe.isEmpty(other)) {
+                    other.forEach((k, v)->this.put(k, v)); 
+                }
+            }
+            
+            @Override
+            public V put(K key, Can<K> aliases, V value) {
+                putAliasKeys(key, aliases);
+                return delegate.put(key, value);
+            }
+            
+            @Override
+            public boolean containsKey(Object keyOrAliasKey) {
+                return delegate.containsKey(keyOrAliasKey) ||
+                    containsAliasKey(keyOrAliasKey);
+            }
+            
+
+            @Override
+            public V get(Object keyOrAliasKey) {
+                val v = delegate.get(keyOrAliasKey);
+                if(v!=null) {
+                    return v;
+                }
+                return getByAliasKey(keyOrAliasKey);
+            }
+            
+            @Override 
+            public V remove(Object key) { 
+                removeAliasKeysOf(key);
+                return delegate.remove(key); 
+            }
+            
+            @Override 
+            public void clear() {
+                delegate.clear(); 
+                clearAliasKeys();
+            }
+            
+            // -- HELPER
+            
+            private final Map<K, KeyPair<K>> pairByAliasKey = _Maps.newHashMap();
+            
+            private void putAliasKeys(K key, Can<K> aliasKeys) {
+                if(aliasKeys.isNotEmpty()) {
+                    val keyPair = KeyPair.of(key, aliasKeys);
+                    for(val aliasKey : aliasKeys) {
+                        val existing = pairByAliasKey.put(aliasKey, keyPair);
+                        if(existing!=null) {
+                            throw _Exceptions.illegalArgument("alias key collision %s", aliasKey);
+                        }
+                    }
+                }
+            }
+            
+            private V getByAliasKey(Object aliasKey) {
+                val keyPair = pairByAliasKey.get(aliasKey);
+                if(keyPair!=null) {
+                    return delegate.get(keyPair.getKey()); 
+                }
+                return null;
+            }
+
+            private boolean containsAliasKey(Object aliasKey) {
+                return pairByAliasKey.containsKey(aliasKey);
+            }
+            
+            private void removeAliasKeysOf(final Object key) {
+                //XXX this implementation is slow for large alias maps, since we traverse the entire map
+                pairByAliasKey.entrySet()
+                .removeIf(entry->{
+                    val keyPair = entry.getValue();
+                    return keyPair.getKey().equals(key);
+                });
+                
+            }
+            
+            private void clearAliasKeys() {
+                pairByAliasKey.clear();
+            }
+            
+
+        };
+    }
 
     // --
 
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Multimaps.java b/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Multimaps.java
index 67bffff..d0a20c4 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Multimaps.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Multimaps.java
@@ -195,6 +195,7 @@ public class _Multimaps {
     public static <K, V> ListMultimap<K, V> newListMultimap(
             final Supplier<Map<K, List<V>>> mapFactory,
             final Supplier<List<V>> elementCollectionFactory){
+        
         requires(mapFactory, "mapFactory");
         requires(elementCollectionFactory, "elementCollectionFactory");
 
@@ -231,7 +232,8 @@ public class _Multimaps {
 
     public static <K, V, S extends Set<V>> SetMultimap<K, V> newSetMultimap(
             final Supplier<? extends Map<K, S>> mapFactory,
-                    final Supplier<S> elementCollectionFactory){
+            final Supplier<S> elementCollectionFactory){
+        
         requires(mapFactory, "mapFactory");
         requires(elementCollectionFactory, "elementCollectionFactory");
 
@@ -269,6 +271,7 @@ public class _Multimaps {
     public static <K1, K2, V> MapMultimap<K1, K2, V> newMapMultimap(
             final Supplier<Map<K1, Map<K2, V>>> mapFactory,
             final Supplier<Map<K2, V>> elementMapFactory){
+        
         requires(mapFactory, "mapFactory");
         requires(elementMapFactory, "elementMapFactory");
 
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Sets.java b/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Sets.java
index 488d349..7662702 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Sets.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/collections/_Sets.java
@@ -298,5 +298,4 @@ public final class _Sets {
                 .collect(Collectors.toCollection(TreeSet::new)));
     }
 
-
 }
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/context/_Context.java b/core/commons/src/main/java/org/apache/isis/commons/internal/context/_Context.java
index acb3790..1be875e 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/context/_Context.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/context/_Context.java
@@ -26,7 +26,7 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Function;
 import java.util.function.Supplier;
 
-import org.apache.isis.commons.collections.Bin;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.commons.internal.collections._Lists;
 
@@ -275,7 +275,7 @@ public final class _Context {
      * @param type - the key into the thread-local store
      * @return
      */
-    public static <T> Bin<T> threadLocalGet(Class<? super T> type) {
+    public static <T> Can<T> threadLocalGet(Class<? super T> type) {
         return _Context_ThreadLocal.get(type);
     }
 
@@ -286,7 +286,7 @@ public final class _Context {
      * @param requiredType - the required type of the elements in the returned bin
      * @return
      */
-    public static <T> Bin<T> threadLocalSelect(Class<? super T> type, Class<? super T> requiredType) {
+    public static <T> Can<T> threadLocalSelect(Class<? super T> type, Class<? super T> requiredType) {
         return _Context_ThreadLocal.select(type, requiredType);
     }
 
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/context/_Context_ThreadLocal.java b/core/commons/src/main/java/org/apache/isis/commons/internal/context/_Context_ThreadLocal.java
index 04267de..1b81572 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/context/_Context_ThreadLocal.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/context/_Context_ThreadLocal.java
@@ -21,7 +21,7 @@ package org.apache.isis.commons.internal.context;
 
 import java.util.Map;
 
-import org.apache.isis.commons.collections.Bin;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.commons.internal.collections._Maps;
 import org.apache.isis.commons.internal.collections._Multimaps;
@@ -65,15 +65,15 @@ final class _Context_ThreadLocal {
         val threadLocalMap = getOrCreateThreadLocalMap();
         threadLocalMap
         .compute(type, (k, v) -> v == null 
-        ? Bin.<T>ofSingleton(variant)
-                : Bin.<T>concat(_Casts.uncheckedCast(v), variant));
+        ? Can.<T>ofSingleton(variant)
+                : Can.<T>concat(_Casts.uncheckedCast(v), variant));
 
         val key = THREAD_LOCAL_MAP_KEY.get();
 
         return ()->{MAPS_BY_KEY.remove(key);};
     }
 
-    static <T> Bin<T> select(Class<? super T> type, Class<? super T> instanceOf) {
+    static <T> Can<T> select(Class<? super T> type, Class<? super T> instanceOf) {
         val bin = _Context_ThreadLocal.<T>get(type);
         return bin.filter(t -> isInstanceOf(t, instanceOf));
     }
@@ -82,14 +82,14 @@ final class _Context_ThreadLocal {
         return type.isAssignableFrom(obj.getClass());
     }
 
-    static <T> Bin<T> get(Class<? super T> type) {
+    static <T> Can<T> get(Class<? super T> type) {
         val threadLocalMap = getThreadLocalMap();
         if(threadLocalMap==null) {
-            return Bin.empty();
+            return Can.empty();
         }
         val bin = threadLocalMap.get(type);
         if(bin==null) {
-            return Bin.empty();	
+            return Can.empty();	
         }
         return _Casts.uncheckedCast(bin);
     }
@@ -129,22 +129,22 @@ final class _Context_ThreadLocal {
             InheritableThreadLocal.withInitial(()->ThreadKey.of(Thread.currentThread()));
 
 
-    private final static _Multimaps.MapMultimap<ThreadKey, Class<?>, Bin<?>> MAPS_BY_KEY = 
+    private final static _Multimaps.MapMultimap<ThreadKey, Class<?>, Can<?>> MAPS_BY_KEY = 
             _Multimaps.newConcurrentMapMultimap(); 
 
-    private static Map<Class<?>, Bin<?>> getThreadLocalMap() {
+    private static Map<Class<?>, Can<?>> getThreadLocalMap() {
         val key = THREAD_LOCAL_MAP_KEY.get(); // non-null
         val threadLocalMap = MAPS_BY_KEY.get(key); // might be null
         return threadLocalMap;
     }
 
-    private static Map<Class<?>, Bin<?>> getOrCreateThreadLocalMap() {
+    private static Map<Class<?>, Can<?>> getOrCreateThreadLocalMap() {
         val key = THREAD_LOCAL_MAP_KEY.get(); // non-null
         val threadLocalMap = MAPS_BY_KEY.get(key); // might be null
         if(threadLocalMap!=null) {
             return threadLocalMap;
         }
-        val map = _Maps.<Class<?>, Bin<?>>newHashMap();
+        val map = _Maps.<Class<?>, Can<?>>newHashMap();
         MAPS_BY_KEY.put(key, map);
         return map;
     }
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/IocContainer.java b/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/IocContainer.java
index 15d88ee..1f178bf 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/IocContainer.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/IocContainer.java
@@ -26,7 +26,7 @@ import java.util.stream.Stream;
 
 import javax.annotation.Nullable;
 
-import org.apache.isis.commons.collections.Bin;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 
 /**
@@ -38,9 +38,9 @@ public interface IocContainer {
 
     Stream<ManagedBeanAdapter> streamAllBeans();
 
-    <T> Bin<T> select(Class<T> requiredType);
+    <T> Can<T> select(Class<T> requiredType);
     
-    <T> Bin<T> select(Class<T> requiredType, Set<Annotation> qualifiersRequired);
+    <T> Can<T> select(Class<T> requiredType, Set<Annotation> qualifiersRequired);
 
     /**
      * @return IoC managed singleton wrapped in an Optional
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/ManagedBeanAdapter.java b/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/ManagedBeanAdapter.java
index af52e81..42ac32b 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/ManagedBeanAdapter.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/ManagedBeanAdapter.java
@@ -18,7 +18,7 @@
  */
 package org.apache.isis.commons.internal.ioc;
 
-import org.apache.isis.commons.collections.Bin;
+import org.apache.isis.commons.collections.Can;
 
 /**
  * @since 2.0
@@ -26,7 +26,7 @@ import org.apache.isis.commons.collections.Bin;
 public interface ManagedBeanAdapter { 
 
     String getId();
-    Bin<?> getInstance();
+    Can<?> getInstance();
     Class<?> getBeanClass();
 
     boolean isCandidateFor(Class<?> requiredType);
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/cdi/BeanAdapterCDI.java b/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/cdi/BeanAdapterCDI.java
index 276c588..dd6e5de 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/cdi/BeanAdapterCDI.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/cdi/BeanAdapterCDI.java
@@ -20,7 +20,7 @@ package org.apache.isis.commons.internal.ioc.cdi;
 
 import javax.enterprise.inject.spi.Bean;
 
-import org.apache.isis.commons.collections.Bin;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.ioc.ManagedBeanAdapter;
 
 import lombok.Value;
@@ -33,7 +33,7 @@ final class BeanAdapterCDI implements ManagedBeanAdapter {
     private final Bean<?> bean;
 
     @Override
-    public Bin<?> getInstance() {
+    public Can<?> getInstance() {
         val type = bean.getBeanClass();
         return _CDI.select(type, bean.getQualifiers());
     }
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/cdi/_CDI.java b/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/cdi/_CDI.java
index 0b581dd..e7fab62 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/cdi/_CDI.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/cdi/_CDI.java
@@ -38,7 +38,7 @@ import javax.enterprise.inject.spi.CDIProvider;
 import javax.enterprise.util.AnnotationLiteral;
 import javax.inject.Qualifier;
 
-import org.apache.isis.commons.collections.Bin;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.context._Context;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.commons.internal.functions._Functions.CheckedRunnable;
@@ -108,7 +108,7 @@ public final class _CDI {
      * @param qualifiers
      * @return non-null {@code Bin}
      */
-    public static <T> Bin<T> select(final Class<T> subType, Collection<Annotation> qualifiers) {
+    public static <T> Can<T> select(final Class<T> subType, Collection<Annotation> qualifiers) {
         if(isEmpty(qualifiers)) {
             return select(subType);
         }
@@ -117,8 +117,8 @@ public final class _CDI {
 
         return cdi()
                 .map(cdi->tryGet(()->cdi.select(subType, _qualifiers)))
-                .map(instance->Bin.ofInstance(instance))
-                .orElse(Bin.empty());
+                .map(instance->Can.ofInstance(instance))
+                .orElse(Can.empty());
     }
 
     /**
@@ -126,11 +126,11 @@ public final class _CDI {
      * @param subType
      * @return non-null {@code Bin}
      */
-    public static <T> Bin<T> select(final Class<T> subType) {
+    public static <T> Can<T> select(final Class<T> subType) {
         return cdi()
                 .map(cdi->tryGet(()->cdi.select(subType)))
-                .map(instance->Bin.ofInstance(instance))
-                .orElse(Bin.empty());
+                .map(instance->Can.ofInstance(instance))
+                .orElse(Can.empty());
     }
 
 
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/spring/BeanAdapterSpring.java b/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/spring/BeanAdapterSpring.java
index d2b5107..b4d8909 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/spring/BeanAdapterSpring.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/spring/BeanAdapterSpring.java
@@ -20,7 +20,7 @@ package org.apache.isis.commons.internal.ioc.spring;
 
 import org.springframework.beans.factory.ObjectProvider;
 
-import org.apache.isis.commons.collections.Bin;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.ioc.ManagedBeanAdapter;
 
 import lombok.Value;
@@ -34,9 +34,9 @@ final class BeanAdapterSpring implements ManagedBeanAdapter {
     private final ObjectProvider<?> beanProvider;
 
     @Override
-    public Bin<?> getInstance() {
+    public Can<?> getInstance() {
         val allMatchingBeans = beanProvider.stream(); 
-        return Bin.ofStream(allMatchingBeans);
+        return Can.ofStream(allMatchingBeans);
     }
 
     @Override
diff --git a/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/spring/IocContainerSpring.java b/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/spring/IocContainerSpring.java
index 381aa67..8a93664 100644
--- a/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/spring/IocContainerSpring.java
+++ b/core/commons/src/main/java/org/apache/isis/commons/internal/ioc/spring/IocContainerSpring.java
@@ -28,7 +28,7 @@ import javax.annotation.Nullable;
 import org.springframework.context.ApplicationContext;
 import org.springframework.core.ResolvableType;
 
-import org.apache.isis.commons.collections.Bin;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.collections._Sets;
 import org.apache.isis.commons.internal.ioc.IocContainer;
@@ -75,15 +75,15 @@ public class IocContainerSpring implements IocContainer {
     }
     
     @Override
-    public <T> Bin<T> select(final Class<T> requiredType) {
+    public <T> Can<T> select(final Class<T> requiredType) {
         requires(requiredType, "requiredType");
 
         val allMatchingBeans = springContext.getBeanProvider(requiredType).orderedStream();
-        return Bin.ofStream(allMatchingBeans);
+        return Can.ofStream(allMatchingBeans);
     }
 
     @Override
-    public <T> Bin<T> select(
+    public <T> Can<T> select(
             final Class<T> requiredType, 
             @Nullable Set<Annotation> qualifiersRequired) {
 
@@ -93,7 +93,7 @@ public class IocContainerSpring implements IocContainer {
                 .orderedStream();
 
         if(_NullSafe.isEmpty(qualifiersRequired)) {
-            return Bin.ofStream(allMatchingBeans);
+            return Can.ofStream(allMatchingBeans);
         }
 
         final Predicate<T> hasAllQualifiers = t -> {
@@ -101,7 +101,7 @@ public class IocContainerSpring implements IocContainer {
             return qualifiersPresent.containsAll(qualifiersRequired);
         };
 
-        return Bin.ofStream(allMatchingBeans
+        return Can.ofStream(allMatchingBeans
                 .filter(hasAllQualifiers));
     }
     
diff --git a/core/commons/src/test/java/org/apache/isis/commons/internal/collections/_MapsTest.java b/core/commons/src/test/java/org/apache/isis/commons/internal/collections/_MapsTest.java
new file mode 100644
index 0000000..4cbcafd
--- /dev/null
+++ b/core/commons/src/test/java/org/apache/isis/commons/internal/collections/_MapsTest.java
@@ -0,0 +1,127 @@
+/*
+ *  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.commons.internal.collections;
+
+import java.util.HashMap;
+
+import org.junit.jupiter.api.Test;
+
+import org.apache.isis.commons.collections.Can;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import lombok.val;
+
+class _MapsTest {
+    
+    @Test
+    void aliasMap_shouldAllowLookupByAliasKey() {
+        
+        val aliasMap = _Maps.<String, String>newAliasMap(HashMap::new);
+        
+        aliasMap.put("key1", "value1");
+        aliasMap.put("key2", Can.ofArray(new String[] {"alias2a", "alias2b"}), "value2");
+        aliasMap.put("key3", Can.empty(), "value3");
+        
+        assertTrue(aliasMap.containsKey("key1"));
+        assertEquals("value1", aliasMap.get("key1"));
+
+        assertTrue(aliasMap.containsKey("key2"));
+        assertEquals("value2", aliasMap.get("key2"));
+        assertEquals("value2", aliasMap.get("alias2a"));
+        assertEquals("value2", aliasMap.get("alias2b"));
+        
+        assertTrue(aliasMap.containsKey("key3"));
+        assertEquals("value3", aliasMap.get("key3"));
+        
+        
+    }
+    
+    @Test
+    void aliasMap_shouldAlsoClearAliases() {
+        
+        val aliasMap = _Maps.<String, String>newAliasMap(HashMap::new);
+        
+        aliasMap.put("key1", "value1");
+        aliasMap.put("key2", Can.ofArray(new String[] {"alias2a", "alias2b"}), "value2");
+        aliasMap.put("key3", Can.empty(), "value3");
+        
+        aliasMap.clear();
+        
+        assertFalse(aliasMap.containsKey("key1"));
+        assertNull(aliasMap.get("key1"));
+        
+        assertFalse(aliasMap.containsKey("key2"));
+        assertNull(aliasMap.get("key2"));
+        assertNull(aliasMap.get("alias2a"));
+        assertNull(aliasMap.get("alias2b"));
+        
+        assertFalse(aliasMap.containsKey("key3"));
+        assertNull(aliasMap.get("key3"));
+        
+    }
+    
+    @Test
+    void aliasMap_shouldHonorRemoval() {
+        
+        val aliasMap = _Maps.<String, String>newAliasMap(HashMap::new);
+        
+        aliasMap.put("key1", "value1");
+        aliasMap.put("key2", Can.ofArray(new String[] {"alias2a", "alias2b"}), "value2");
+        aliasMap.put("key3", Can.empty(), "value3");
+        
+        aliasMap.remove("key1");
+        aliasMap.remove("key2");
+        aliasMap.remove("key3");
+        
+        assertFalse(aliasMap.containsKey("key1"));
+        assertNull(aliasMap.get("key1"));
+        
+        assertFalse(aliasMap.containsKey("key2"));
+        assertNull(aliasMap.get("key2"));
+        assertNull(aliasMap.get("alias2a"));
+        assertNull(aliasMap.get("alias2b"));
+        
+        assertFalse(aliasMap.containsKey("key3"));
+        assertNull(aliasMap.get("key3"));
+        
+        // re-adding previously removed should not throw
+        aliasMap.put("key2", Can.ofArray(new String[] {"alias2a", "alias2b"}), "value2");
+        
+    }
+    
+    @Test
+    void aliasMap_shouldThrowOnAliasKeyCollision() {
+        
+        val aliasMap = _Maps.<String, String>newAliasMap(HashMap::new);
+        
+        aliasMap.put("key1", Can.ofArray(new String[] {"alias1a", "alias1b"}), "value1");
+        
+        assertThrows(IllegalArgumentException.class, ()->{
+            aliasMap.put("key2", Can.ofArray(new String[] {"alias1a"}), "value2");
+        });
+        
+    }
+    
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/adapter/loader/ObjectLoader_builtinHandlers.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/adapter/loader/ObjectLoader_builtinHandlers.java
index f4bfeb5..76c9f0f 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/adapter/loader/ObjectLoader_builtinHandlers.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/adapter/loader/ObjectLoader_builtinHandlers.java
@@ -21,7 +21,7 @@ package org.apache.isis.metamodel.adapter.loader;
 import java.lang.reflect.Array;
 import java.lang.reflect.Modifier;
 
-import org.apache.isis.commons.collections.Bin;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.commons.internal.ioc.ManagedBeanAdapter;
 import org.apache.isis.metamodel.MetaModelContext;
@@ -97,7 +97,7 @@ final class ObjectLoader_builtinHandlers {
             val servicePojo = metaModelContext.getServiceRegistry()
                 .lookupRegisteredBeanById(beanName)
                 .map(ManagedBeanAdapter::getInstance)
-                .flatMap(Bin::getFirst)
+                .flatMap(Can::getFirst)
                 .orElseThrow(()->_Exceptions.noSuchElement(
                         "loader: %s loading beanName %s", 
                         this.getClass().getName(), beanName));
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/consent/InteractionAdvisor.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/consent/InteractionAdvisor.java
index 0d60c41..d8a8238 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/consent/InteractionAdvisor.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/consent/InteractionAdvisor.java
@@ -22,6 +22,7 @@ package org.apache.isis.metamodel.consent;
 import java.util.Map;
 import java.util.function.Consumer;
 
+import org.apache.isis.commons.internal.exceptions._Exceptions;
 import org.apache.isis.metamodel.facetapi.Facet;
 import org.apache.isis.metamodel.facetapi.FacetHolder;
 import org.apache.isis.metamodel.interactions.InteractionAdvisorFacet;
@@ -82,18 +83,21 @@ public interface InteractionAdvisor {
         }
 
         @Override
-        public void addAlias(Class<? extends Facet> alias) {
+        public void addContributedFacet(Facet contributedFacet) {
+            throw _Exceptions.unsupportedOperation();
         }
 
         @Override
-        public void forEachAlias(Consumer<Class<? extends Facet>> onAlias) {
+        public void forEachContributedFacet(Consumer<Facet> onContributedFacet) {
+            throw _Exceptions.unsupportedOperation();
         }
 
         @Override
-        public boolean hasAlias(Class<? extends Facet> alias) {
-            return false;
+        public Class<? extends Facet> facetAliasType() {
+            return null;
         }
 
+
     };
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facetapi/Facet.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facetapi/Facet.java
index a984b4a..cff8cd7 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facetapi/Facet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facetapi/Facet.java
@@ -100,22 +100,24 @@ public interface Facet extends FacetWithAttributes {
     // -- FACET ALIAS SUPPORT
     
     /**
-     * Add an alias by which the facet can be looked up.
+     * Adds a facet this facet contributes.
      * @since 2.0
      */
-    void addAlias(Class<? extends Facet> alias);
+    void addContributedFacet(Facet contributedFacet);
 
     /**
-     * Traverses all aliases (if any).
+     * Traverses all contributed facets (if any).
      * @since 2.0
      */
-    void forEachAlias(Consumer<Class<? extends Facet>> onAlias);
+    void forEachContributedFacet(Consumer<Facet> onContributedFacet);
 
     /**
-     * Whether has an alias by which the facet can be looked up.
+     * An alternative type this Facet can be looked up via {@link FacetHolder#getFacet(Class)}.
+     * @apiNote like {@link #facetType()} the alias must be unique within any facet-holder's 
+     * registered facet-types, otherwise an {@link IllegalArgumentException} is thrown during
+     * facet-processing; this is to ensure unambiguous lookup of facets by their alias type 
      * @since 2.0
      */
-    boolean hasAlias(Class<? extends Facet> alias);
-
+    Class<? extends Facet> facetAliasType();
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facetapi/FacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facetapi/FacetAbstract.java
index c25059c..986c55a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facetapi/FacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facetapi/FacetAbstract.java
@@ -30,6 +30,7 @@ import org.apache.isis.metamodel.MetaModelContext;
 
 import static org.apache.isis.commons.internal.base._With.requires;
 
+import lombok.Setter;
 import lombok.val;
 
 
@@ -43,7 +44,8 @@ public abstract class FacetAbstract implements Facet, MetaModelContext.Delegatin
     private Facet underlyingFacet;
 
     private final Class<? extends Facet> facetType;
-    private Set<Class<? extends Facet>> facetAliasTypes; // lazy init
+    @Setter private Class<? extends Facet> facetAliasType;
+    private Set<Facet> contributedFacets; // lazy init
     
     private final boolean derived;
     private FacetHolder holder;
@@ -78,7 +80,12 @@ public abstract class FacetAbstract implements Facet, MetaModelContext.Delegatin
     public final Class<? extends Facet> facetType() {
         return facetType;
     }
-
+    
+    @Override
+    public Class<? extends Facet> facetAliasType() {
+        return facetAliasType!=facetType ? facetAliasType : null; // avoids facetAliasType equals facetType 
+    }
+    
     @Override
     public FacetHolder getFacetHolder() {
         return holder;
@@ -259,32 +266,22 @@ public abstract class FacetAbstract implements Facet, MetaModelContext.Delegatin
     public static interface Validating {
     }
 
-    // -- FACET ALIAS SUPPORT
+    // -- CONTRIBUTED FACET SUPPORT
     
     @Override
-    public void addAlias(Class<? extends Facet> alias) {
-        if(facetAliasTypes==null) {
-            facetAliasTypes = _Sets.newHashSet();
+    public void addContributedFacet(Facet contributedFacet) {
+        if(contributedFacets==null) {
+            contributedFacets = _Sets.newHashSet();
         }
-        facetAliasTypes.add(alias);
+        contributedFacets.add(contributedFacet);
     }
     
     @Override
-    public void forEachAlias(Consumer<Class<? extends Facet>> onAlias) {
-        if(facetAliasTypes!=null) {
-            facetAliasTypes.forEach(onAlias);
+    public void forEachContributedFacet(Consumer<Facet> onContributedFacet) {
+        if(contributedFacets!=null) {
+            contributedFacets.forEach(onContributedFacet);
         }
     }
-    
-    @Override
-    public boolean hasAlias(Class<? extends Facet> alias) {
-        if(facetAliasTypes==null) {
-            return false;
-        }
-        return facetAliasTypes.contains(alias);
-    }
-
-    
 
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facetapi/FacetHolder.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facetapi/FacetHolder.java
index 2cf6923..4358ca1 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facetapi/FacetHolder.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facetapi/FacetHolder.java
@@ -46,22 +46,21 @@ public interface FacetHolder {
 
     /**
      * Whether there is a facet registered of the specified type that is not a
-     * {@link Facet#isFallback() no-op}.
-     *
+     * {@link Facet#isFallback() fallback} .
      * <p>
      * Convenience; saves having to {@link #getFacet(Class)} and then check if
-     * <tt>null</tt> and not a no-op.
+     * <tt>null</tt> and not a fallback.
      */
-    default boolean containsDoOpFacet(Class<? extends Facet> facetType) {
+    default boolean containsNonFallbackFacet(Class<? extends Facet> facetType) {
         val facet = getFacet(facetType);
         return facet != null && !facet.isFallback();
     }
 
     /**
-     * As {@link #containsDoOpFacet(Class)}, which additional requirement that the
-     * facet is not {@link Facet#isDerived()}.
+     * As {@link #containsNonFallbackFacet(Class)}, with additional requirement, that the
+     * facet is <i>explicit</i>, not {@link Facet#isDerived() derived}.
      */
-    default boolean containsDoOpNotDerivedFacet(Class<? extends Facet> facetType) {
+    default boolean containsExplicitNonFallbackFacet(Class<? extends Facet> facetType) {
         val facet = getFacet(facetType);
         return facet != null && !facet.isFallback() && !facet.isDerived();
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facetapi/FacetHolderImpl.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facetapi/FacetHolderImpl.java
index 3ece3fd..365fedc 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facetapi/FacetHolderImpl.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facetapi/FacetHolderImpl.java
@@ -19,14 +19,14 @@
 
 package org.apache.isis.metamodel.facetapi;
 
+import java.util.HashMap;
 import java.util.Map;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
 import java.util.stream.Stream;
 
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._Lazy;
-import org.apache.isis.commons.internal.collections._Sets;
+import org.apache.isis.commons.internal.collections._Maps;
+import org.apache.isis.commons.internal.collections._Maps.AliasMap;
 import org.apache.isis.metamodel.MetaModelContext;
 import org.apache.isis.metamodel.MetaModelContextAware;
 
@@ -44,97 +44,125 @@ public class FacetHolderImpl implements FacetHolder, MetaModelContextAware {
     @Getter(onMethod = @__(@Override)) @Setter(onMethod = @__(@Override))
     private MetaModelContext metaModelContext;
     
-    private final Map<Class<? extends Facet>, Facet> facetsByClass = new ConcurrentHashMap<>();
-    private final _Lazy<Set<Facet>> snapshot = _Lazy.threadSafe(this::snapshot);
-
-    private Set<Facet> snapshot() {
-        val snapshot = _Sets.<Facet>newHashSet();
-        facetsByClass.values().forEach(snapshot::add);
-        return snapshot;
-    }
+    private final Map<Class<? extends Facet>, Facet> facetsByType = _Maps.newHashMap();
+    private final Object $lock = new Object();
     
     @Override
     public boolean containsFacet(Class<? extends Facet> facetType) {
-        return facetsByClass.containsKey(facetType);
+        synchronized($lock) {
+            return snapshot.get().containsKey(facetType);
+        }
     }
 
     @Override
     public void addFacet(Facet facet) {
-        addFacet(facet.facetType(), facet);
+        synchronized($lock) {
+            val changed = addFacetOrKeepExisting(facetsByType, facet);
+            if(changed) {
+                snapshot.clear(); //invalidate
+            }
+        }
     }
 
     @Override
     public <T extends Facet> T getFacet(Class<T> facetType) {
-        return uncheckedCast(facetsByClass.get(facetType));
+        synchronized($lock) {
+            return uncheckedCast(snapshot.get().get(facetType));
+        }
     }
 
     @Override
     public Stream<Facet> streamFacets() {
-        synchronized(snapshot) {
-            return snapshot.get().stream(); // consumers should play nice and don't take too long  
+        synchronized($lock) {
+            return snapshot.get().values().stream(); // consumers should play nice and don't take too long  
         }
     }
 
     @Override
     public int getFacetCount() {
-        synchronized(snapshot) {
+        synchronized($lock) {
             return snapshot.get().size();    
         }
     }
     
     @Override
     public void addOrReplaceFacet(Facet facet) {
-        
-        Optional.ofNullable(getFacet(facet.facetType()))
-        .filter(each -> facet.getClass() == each.getClass())
-        .ifPresent(existingFacet -> {
-            remove(existingFacet);
-            val underlyingFacet = existingFacet.getUnderlyingFacet();
-            facet.setUnderlyingFacet(underlyingFacet);
-        } );
-        
-        addFacet(facet);
+        synchronized($lock) {
+            val facetType = facet.facetType();
+            val existingFacet = getFacet(facetType);
+            if (existingFacet != null) {
+                remove(existingFacet);
+                val underlyingFacet = existingFacet.getUnderlyingFacet();
+                facet.setUnderlyingFacet(underlyingFacet);
+            }
+            
+            addFacet(facet);
+        }
     }
 
     // -- HELPER
+    
+    private final _Lazy<Map<Class<? extends Facet>, Facet>> snapshot = _Lazy.threadSafe(this::snapshot);
+
+    // collect all facet information provided with the top-level facets (contributed facets and aliases)
+    private Map<Class<? extends Facet>, Facet> snapshot() {
+        val snapshot = _Maps.<Class<? extends Facet>, Facet>newAliasMap(HashMap::new);
+        facetsByType.values().forEach(topLevelFacet->{
+             
+            snapshot.put(
+                    topLevelFacet.facetType(), 
+                    Can.ofNullable(topLevelFacet.facetAliasType()), 
+                    topLevelFacet);
+
+            // honor contributed facets via recursive lookup
+            collectChildren(snapshot, topLevelFacet);
+
+
+        });
+        return snapshot;
+    }
 
-    private void addFacet(Class<? extends Facet> facetType, Facet facet) {
-        val existingFacet = getFacet(facetType);
+    private void collectChildren(AliasMap<Class<? extends Facet>, Facet> target, Facet parentFacet) {
+        parentFacet.forEachContributedFacet(child->{
+            val added = addFacetOrKeepExisting(target, child);
+            if(added) {
+                collectChildren(target, child); 
+            }
+        });        
+    }
+
+    private boolean addFacetOrKeepExisting(
+            Map<Class<? extends Facet>, Facet> facetsByType,
+            Facet facet) {
+        
+        val existingFacet = facetsByType.get(facet.facetType());
+        
+        val addOrKeep = whichPrecedesTheOther(existingFacet, facet);
+        if(addOrKeep==facet) {
+            facetsByType.put(facet.facetType(), facet);
+            return true;
+        }
+        return false;
+    }
+    
+    private void remove(Facet topLevelFacet) {
+        snapshot.clear(); //invalidate
+        facetsByType.remove(topLevelFacet.facetType());
+    }
+    
+    // also has side-effects (not really suggested by the naming)
+    private Facet whichPrecedesTheOther(Facet existingFacet, Facet facet) {
         if (existingFacet == null || existingFacet.isFallback()) {
-            put(facetType, facet);
-            return;
+            return facet;
         }
         if (!facet.alwaysReplace()) {
-            return; //eg. ValueSemanticsProviderAndFacetAbstract is alwaysReplace=false
+            return existingFacet; //eg. ValueSemanticsProviderAndFacetAbstract is alwaysReplace=false
         }
         if (facet.isDerived() && !existingFacet.isDerived()) {
-            return;
+            return existingFacet;
         }
         facet.setUnderlyingFacet(existingFacet);
-        put(facetType, facet);
-    }
-
-    private void put(Class<? extends Facet> facetType, Facet facet) {
-        synchronized(snapshot) {
-            snapshot.clear();
-            facetsByClass.put(facetType, facet);
-            facet.forEachAlias(aliasType->facetsByClass.put(aliasType, facet));
-        }
+        return facet;
     }
-    
-    private void remove(Facet facet) {
-        synchronized(snapshot) {
-            snapshot.clear();
-            facetsByClass.remove(facet.facetType());
-            // for all the registered aliases that point to the given facet, remove ...
-            facet.forEachAlias(aliasType->{
-                val aliasFor = facetsByClass.get(aliasType);
-                if(facet == aliasFor) {
-                    facetsByClass.remove(aliasType);
-                }
-            });
-        }
-    }
-    
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facetapi/MetaModelRefiner.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facetapi/MetaModelRefiner.java
index 2dad5f7..d1922bc 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facetapi/MetaModelRefiner.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facetapi/MetaModelRefiner.java
@@ -20,7 +20,7 @@
 package org.apache.isis.metamodel.facetapi;
 
 import org.apache.isis.applib.services.registry.ServiceRegistry;
-import org.apache.isis.commons.collections.Bin;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.metamodel.progmodel.ProgrammingModel;
 
 
@@ -35,7 +35,7 @@ public interface MetaModelRefiner {
 
     // -- LOOKUP ALL REFINERS
 
-    static Bin<MetaModelRefiner> getAll(ServiceRegistry serviceRegistry) {
+    static Can<MetaModelRefiner> getAll(ServiceRegistry serviceRegistry) {
         return serviceRegistry.select(MetaModelRefiner.class);
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/actions/action/ActionChoicesForCollectionParameterFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/actions/action/ActionChoicesForCollectionParameterFacetFactory.java
index 8f18efc..a9039a7 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/actions/action/ActionChoicesForCollectionParameterFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/actions/action/ActionChoicesForCollectionParameterFacetFactory.java
@@ -132,7 +132,7 @@ implements MetaModelRefiner {
                         }
 
                         final ObjectSpecification parameterType = parameter.getSpecification();
-                        if(parameterType.containsDoOpFacet(AutoCompleteFacet.class)) {
+                        if(parameterType.containsNonFallbackFacet(AutoCompleteFacet.class)) {
                             return;
                         }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/actions/layout/ActionLayoutFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/actions/layout/ActionLayoutFacetFactory.java
index 1daf745..1c309e9 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/actions/layout/ActionLayoutFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/actions/layout/ActionLayoutFacetFactory.java
@@ -161,7 +161,7 @@ public class ActionLayoutFacetFactory extends FacetFactoryAbstract implements Co
 
         // position
         ActionPositionFacet actionPositionFacet = null;
-        if(! holder.containsDoOpFacet(ActionPositionFacet.class)) {
+        if(! holder.containsNonFallbackFacet(ActionPositionFacet.class)) {
             actionPositionFacet = new ActionPositionFacetFallback(holder);
         }
         super.addFacet(actionPositionFacet);
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/actions/layout/PromptStyleFacetForActionLayoutAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/actions/layout/PromptStyleFacetForActionLayoutAnnotation.java
index 4822247..68b049a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/actions/layout/PromptStyleFacetForActionLayoutAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/actions/layout/PromptStyleFacetForActionLayoutAnnotation.java
@@ -60,7 +60,7 @@ public class PromptStyleFacetForActionLayoutAnnotation extends PromptStyleFacetA
                     case AS_CONFIGURED:
 
                         // do not replace
-                        if (holder.containsDoOpFacet(PromptStyleFacet.class)) {
+                        if (holder.containsNonFallbackFacet(PromptStyleFacet.class)) {
                             return null;
                         }
 
@@ -73,7 +73,7 @@ public class PromptStyleFacetForActionLayoutAnnotation extends PromptStyleFacetA
                 })
                 .orElseGet(() -> {
                     // do not replace
-                    if (holder.containsDoOpFacet(PromptStyleFacet.class)) {
+                    if (holder.containsNonFallbackFacet(PromptStyleFacet.class)) {
                         return null;
                     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/all/deficiencies/DeficiencyFacet.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/all/deficiencies/DeficiencyFacet.java
index 539ca10..42ed32b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/all/deficiencies/DeficiencyFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/all/deficiencies/DeficiencyFacet.java
@@ -116,18 +116,18 @@ public final class DeficiencyFacet implements Facet {
     }
 
     @Override
-    public void addAlias(Class<? extends Facet> alias) {
+    public void addContributedFacet(Facet contributedFacet) {
         throw _Exceptions.unsupportedOperation();
     }
 
     @Override
-    public void forEachAlias(Consumer<Class<? extends Facet>> onAlias) {
+    public void forEachContributedFacet(Consumer<Facet> onContributedFacet) {
         throw _Exceptions.unsupportedOperation();
     }
 
     @Override
-    public boolean hasAlias(Class<? extends Facet> alias) {
-        return false;
+    public Class<? extends Facet> facetAliasType() {
+        return null;
     }
 
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/collections/disabled/fromimmutable/DisabledFacetOnCollectionDerivedFromImmutableFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/collections/disabled/fromimmutable/DisabledFacetOnCollectionDerivedFromImmutableFactory.java
index 0c5065b..8a26912 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/collections/disabled/fromimmutable/DisabledFacetOnCollectionDerivedFromImmutableFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/collections/disabled/fromimmutable/DisabledFacetOnCollectionDerivedFromImmutableFactory.java
@@ -35,7 +35,7 @@ public class DisabledFacetOnCollectionDerivedFromImmutableFactory extends FacetF
     public void process(final ProcessMethodContext processMethodContext) {
         final Class<?> declaringClass = processMethodContext.getMethod().getDeclaringClass();
         final ObjectSpecification spec = getSpecificationLoader().loadSpecification(declaringClass);
-        if (spec.containsDoOpFacet(ImmutableFacet.class)) {
+        if (spec.containsNonFallbackFacet(ImmutableFacet.class)) {
             final ImmutableFacet immutableFacet = spec.getFacet(ImmutableFacet.class);
             final FacetedMethod facetHolder = processMethodContext.getFacetHolder();
             super.addFacet(new DisabledFacetOnCollectionDerivedFromImmutable(immutableFacet, facetHolder));
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/jaxb/JaxbFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/jaxb/JaxbFacetFactory.java
index ef1a3c3..664c75a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/jaxb/JaxbFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/jaxb/JaxbFacetFactory.java
@@ -185,7 +185,7 @@ implements MetaModelRefiner {
 
                         properties
                         // ignore derived
-                        .filter(property->property.containsDoOpFacet(PropertySetterFacet.class))
+                        .filter(property->property.containsNonFallbackFacet(PropertySetterFacet.class))
                         .forEach(property->{
                             for (final PropertyValidator adapterValidator : propertyValidators) {
                                 adapterValidator.validate(objectSpec, property, validator);
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/members/cssclass/annotprop/CssClassFacetOnActionFromConfiguredRegexFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/members/cssclass/annotprop/CssClassFacetOnActionFromConfiguredRegexFactory.java
index 6bfd41f..3782327 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/members/cssclass/annotprop/CssClassFacetOnActionFromConfiguredRegexFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/members/cssclass/annotprop/CssClassFacetOnActionFromConfiguredRegexFactory.java
@@ -42,7 +42,7 @@ public class CssClassFacetOnActionFromConfiguredRegexFactory extends FacetFactor
     public void process(final ProcessMethodContext processMethodContext) {
 
         final FacetedMethod facetHolder = processMethodContext.getFacetHolder();
-        if(facetHolder.containsDoOpFacet(CssClassFacet.class)) {
+        if(facetHolder.containsNonFallbackFacet(CssClassFacet.class)) {
             return;
         }
 
@@ -73,7 +73,7 @@ public class CssClassFacetOnActionFromConfiguredRegexFactory extends FacetFactor
         if(!(objectMember instanceof ObjectAction)) {
             return;
         }
-        if(objectMember.containsDoOpFacet(CssClassFacet.class)) {
+        if(objectMember.containsNonFallbackFacet(CssClassFacet.class)) {
             return;
         }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/members/hidden/HiddenFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/members/hidden/HiddenFacetAbstract.java
index f49a45f..8931c8b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/members/hidden/HiddenFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/members/hidden/HiddenFacetAbstract.java
@@ -50,23 +50,23 @@ import org.apache.isis.metamodel.spec.ManagedObject;
 public abstract class HiddenFacetAbstract extends WhereValueFacetAbstract implements HiddenFacet {
 
     public HiddenFacetAbstract(
-            final Class<? extends Facet> facetType,
+            Class<? extends Facet> facetType,
             Where where,
-            final FacetHolder holder) {
+            FacetHolder holder) {
+        
         super(facetType, holder, where);
-        super.addAlias(HiddenFacet.class);
+        super.setFacetAliasType(HiddenFacet.class);
     }
 
     /**
      * For testing only.
      */
-    public HiddenFacetAbstract(Where where, final FacetHolder holder) {
+    public HiddenFacetAbstract(Where where, FacetHolder holder) {
         super(HiddenFacetAbstract.class, holder, where);
-        super.addAlias(HiddenFacet.class);
     }
 
     @Override
-    public String hides(final VisibilityContext<? extends VisibilityEvent> ic) {
+    public String hides(VisibilityContext<? extends VisibilityEvent> ic) {
         return hiddenReason(ic.getTarget(), ic.getWhere());
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/domainobject/editing/ImmutableFacetForDomainObjectAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/domainobject/editing/ImmutableFacetForDomainObjectAnnotation.java
index 9182e1c..2c17f1c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/domainobject/editing/ImmutableFacetForDomainObjectAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/domainobject/editing/ImmutableFacetForDomainObjectAnnotation.java
@@ -51,7 +51,7 @@ public class ImmutableFacetForDomainObjectAnnotation extends ImmutableFacetAbstr
                     case NOT_SPECIFIED:
                     case AS_CONFIGURED:
 
-                        if(holder.containsDoOpFacet(ImmutableFacet.class)) {
+                        if(holder.containsNonFallbackFacet(ImmutableFacet.class)) {
                             // do not replace
                             return null;
                         }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/entity/EntityFacet.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/entity/EntityFacet.java
index 024d82d..95bff0b 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/entity/EntityFacet.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/entity/EntityFacet.java
@@ -34,6 +34,4 @@ public interface EntityFacet extends Facet {
     
     void persist(ObjectSpecification spec, Object pojo);
 
-    
-
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromClassNameFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromClassNameFactory.java
index 597ca89..a253f2a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromClassNameFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/objectspecid/classname/ObjectSpecIdFacetDerivedFromClassNameFactory.java
@@ -56,7 +56,7 @@ implements MetaModelRefiner, ObjectSpecIdFacetFactory {
     public void process(final ProcessObjectSpecIdContext processClassContext) {
         final FacetHolder facetHolder = processClassContext.getFacetHolder();
         // don't trash existing facet
-        if(facetHolder.containsDoOpFacet(ObjectSpecIdFacet.class)) {
+        if(facetHolder.containsNonFallbackFacet(ObjectSpecIdFacet.class)) {
             return;
         }
         final Class<?> cls = processClassContext.getCls();
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/recreatable/DisabledFacetOnCollectionDerivedFromViewModelFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/recreatable/DisabledFacetOnCollectionDerivedFromViewModelFacetFactory.java
index 00043c4..8fd7d3c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/recreatable/DisabledFacetOnCollectionDerivedFromViewModelFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/recreatable/DisabledFacetOnCollectionDerivedFromViewModelFacetFactory.java
@@ -40,7 +40,7 @@ public class DisabledFacetOnCollectionDerivedFromViewModelFacetFactory extends F
         final Class<?> declaringClass = method.getDeclaringClass();
         final ObjectSpecification spec = getSpecificationLoader().loadSpecification(declaringClass);
 
-        if (!spec.containsDoOpFacet(ViewModelFacet.class)) {
+        if (!spec.containsNonFallbackFacet(ViewModelFacet.class)) {
             return;
         }
         final ViewModelFacet facet = spec.getFacet(ViewModelFacet.class);
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/recreatable/DisabledFacetOnPropertyDerivedFromRecreatableObjectFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/recreatable/DisabledFacetOnPropertyDerivedFromRecreatableObjectFacetFactory.java
index cee5ac1..0fbbf81 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/recreatable/DisabledFacetOnPropertyDerivedFromRecreatableObjectFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/recreatable/DisabledFacetOnPropertyDerivedFromRecreatableObjectFacetFactory.java
@@ -39,7 +39,7 @@ public class DisabledFacetOnPropertyDerivedFromRecreatableObjectFacetFactory ext
         final Method method = processMethodContext.getMethod();
         final Class<?> declaringClass = method.getDeclaringClass();
         final ObjectSpecification spec = getSpecificationLoader().loadSpecification(declaringClass);
-        if (!spec.containsDoOpFacet(ViewModelFacet.class)) {
+        if (!spec.containsNonFallbackFacet(ViewModelFacet.class)) {
             return;
         }
         final ViewModelFacet facet = spec.getFacet(ViewModelFacet.class);
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/recreatable/RecreatableObjectFacetDeclarativeInitializingAbstract.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/recreatable/RecreatableObjectFacetDeclarativeInitializingAbstract.java
index adbf342..6c8cc82 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/recreatable/RecreatableObjectFacetDeclarativeInitializingAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/recreatable/RecreatableObjectFacetDeclarativeInitializingAbstract.java
@@ -104,7 +104,7 @@ extends RecreatableObjectFacetAbstract {
 
         properties
         // ignore read-only
-        .filter(property->property.containsDoOpFacet(PropertySetterFacet.class)) 
+        .filter(property->property.containsNonFallbackFacet(PropertySetterFacet.class)) 
         // ignore those explicitly annotated as @NotPersisted
         .filter(property->!property.isNotPersisted())
         .forEach(property->{
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/value/ValueFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/value/ValueFacetAbstract.java
index 88907a5..bb5e61d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/value/ValueFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/value/ValueFacetAbstract.java
@@ -79,6 +79,7 @@ public abstract class ValueFacetAbstract extends FacetAbstract implements ValueF
             final FacetHolder holder) {
 
         super(type(), holder, Derivation.NOT_DERIVED);
+        super.setFacetAliasType(ValueFacet.class);
 
         this.semanticsProvider = semanticsProvider;
 
@@ -109,13 +110,13 @@ public abstract class ValueFacetAbstract extends FacetAbstract implements ValueF
         // ImmutableFacet, if appropriate
         final boolean immutable = semanticsProvider == null || semanticsProvider.isImmutable();
         if (immutable) {
-            facetHolder.addFacet(new ImmutableFacetViaValueSemantics(holder));
+            this.addContributedFacet(new ImmutableFacetViaValueSemantics(holder));
         }
 
         // EqualByContentFacet, if appropriate
         final boolean equalByContent = semanticsProvider == null || semanticsProvider.isEqualByContent();
         if (equalByContent) {
-            facetHolder.addFacet(new EqualByContentFacetViaValueSemantics(holder));
+            this.addContributedFacet(new EqualByContentFacetViaValueSemantics(holder));
         }
 
         if (semanticsProvider != null) {
@@ -123,7 +124,7 @@ public abstract class ValueFacetAbstract extends FacetAbstract implements ValueF
             // install the EncodeableFacet if we've been given an EncoderDecoder
             final EncoderDecoder<?> encoderDecoder = semanticsProvider.getEncoderDecoder();
             if (encoderDecoder != null) {
-                facetHolder.addFacet(new EncodableFacetUsingEncoderDecoder(encoderDecoder, holder));
+                this.addContributedFacet(new EncodableFacetUsingEncoderDecoder(encoderDecoder, holder));
             }
 
             // install the ParseableFacet and other facets if we've been given a
@@ -135,14 +136,14 @@ public abstract class ValueFacetAbstract extends FacetAbstract implements ValueF
                 facetHolder.addFacet(new TypicalLengthFacetUsingParser(parser, holder));
                 final int maxLength = parser.maxLength();
                 if(maxLength >=0) {
-                    facetHolder.addFacet(new MaxLengthFacetUsingParser(parser, holder));
+                    this.addContributedFacet(new MaxLengthFacetUsingParser(parser, holder));
                 }
             }
 
             // install the DefaultedFacet if we've been given a DefaultsProvider
             final DefaultsProvider<?> defaultsProvider = semanticsProvider.getDefaultsProvider();
             if (defaultsProvider != null) {
-                facetHolder.addFacet(new DefaultedFacetUsingDefaultsProvider(defaultsProvider, holder));
+                this.addContributedFacet(new DefaultedFacetUsingDefaultsProvider(defaultsProvider, holder));
             }
         }
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/value/ValueFacetSimple.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/value/ValueFacetSimple.java
index 48280ae..c23b9a1 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/value/ValueFacetSimple.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/object/value/ValueFacetSimple.java
@@ -31,6 +31,7 @@ public class ValueFacetSimple extends FacetAbstract implements ValueFacet {
 
     public ValueFacetSimple(FacetHolder holder) {
         super(type(), holder, Derivation.NOT_DERIVED);
+        super.setFacetAliasType(ValueFacet.class);
     }
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/choices/enums/ActionParameterChoicesFacetDerivedFromChoicesFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/choices/enums/ActionParameterChoicesFacetDerivedFromChoicesFacetFactory.java
index b4226d2..f7a2252 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/choices/enums/ActionParameterChoicesFacetDerivedFromChoicesFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/choices/enums/ActionParameterChoicesFacetDerivedFromChoicesFacetFactory.java
@@ -38,13 +38,13 @@ public class ActionParameterChoicesFacetDerivedFromChoicesFacetFactory extends F
         
         val paramType = processParameterContext.getParameterType();
 
-        if(!getSpecificationLoader().loadSpecification(paramType).containsDoOpFacet(ChoicesFacet.class)) {
+        if(!getSpecificationLoader().loadSpecification(paramType).containsNonFallbackFacet(ChoicesFacet.class)) {
             return;
         }
 
         // don't trample over any existing facets.
         final FacetedMethodParameter facetHolder = processParameterContext.getFacetHolder();
-        if(facetHolder.containsDoOpFacet(ActionParameterChoicesFacet.class)) {
+        if(facetHolder.containsNonFallbackFacet(ActionParameterChoicesFacet.class)) {
             return;
         }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/choices/methodnum/ActionParameterChoicesFacetViaMethodFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/choices/methodnum/ActionParameterChoicesFacetViaMethodFactory.java
index 439db7e..0ce6a24 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/choices/methodnum/ActionParameterChoicesFacetViaMethodFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/choices/methodnum/ActionParameterChoicesFacetViaMethodFactory.java
@@ -84,7 +84,7 @@ public class ActionParameterChoicesFacetViaMethodFactory extends MethodPrefixBas
             processMethodContext.removeMethod(choicesMethod);
 
             final FacetedMethod facetedMethod = processMethodContext.getFacetHolder();
-            if (facetedMethod.containsDoOpFacet(ActionChoicesFacet.class)) {
+            if (facetedMethod.containsNonFallbackFacet(ActionChoicesFacet.class)) {
                 final Class<?> cls = processMethodContext.getCls();
                 throw new MetaModelException(cls + " uses both old and new choices syntax - must use one or other");
             }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/defaults/methodnum/ActionParameterDefaultsFacetViaMethodFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/defaults/methodnum/ActionParameterDefaultsFacetViaMethodFactory.java
index 180e7a5..bc51967 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/defaults/methodnum/ActionParameterDefaultsFacetViaMethodFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/defaults/methodnum/ActionParameterDefaultsFacetViaMethodFactory.java
@@ -85,7 +85,7 @@ public class ActionParameterDefaultsFacetViaMethodFactory extends MethodPrefixBa
             processMethodContext.removeMethod(defaultMethod);
 
             final FacetedMethod facetedMethod = processMethodContext.getFacetHolder();
-            if (facetedMethod.containsDoOpFacet(ActionDefaultsFacet.class)) {
+            if (facetedMethod.containsNonFallbackFacet(ActionDefaultsFacet.class)) {
                 final Class<?> cls2 = processMethodContext.getCls();
                 throw new MetaModelException(cls2 + " uses both old and new default syntax for " + actionMethod.getName() + "(...) - must use one or other");
             }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/properties/choices/enums/PropertyChoicesFacetDerivedFromChoicesFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/properties/choices/enums/PropertyChoicesFacetDerivedFromChoicesFacetFactory.java
index b0e4a99..2620f16 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/properties/choices/enums/PropertyChoicesFacetDerivedFromChoicesFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/properties/choices/enums/PropertyChoicesFacetDerivedFromChoicesFacetFactory.java
@@ -35,7 +35,7 @@ public class PropertyChoicesFacetDerivedFromChoicesFacetFactory extends FacetFac
 
         final Class<?> returnType = processMethodContext.getMethod().getReturnType();
 
-        if(!getSpecificationLoader().loadSpecification(returnType).containsDoOpFacet(ChoicesFacet.class)) {
+        if(!getSpecificationLoader().loadSpecification(returnType).containsNonFallbackFacet(ChoicesFacet.class)) {
             return;
         }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/properties/disabled/fromimmutable/DisabledFacetOnPropertyDerivedFromImmutableFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/properties/disabled/fromimmutable/DisabledFacetOnPropertyDerivedFromImmutableFactory.java
index 7360bae..b05d260 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/properties/disabled/fromimmutable/DisabledFacetOnPropertyDerivedFromImmutableFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/properties/disabled/fromimmutable/DisabledFacetOnPropertyDerivedFromImmutableFactory.java
@@ -37,7 +37,7 @@ public class DisabledFacetOnPropertyDerivedFromImmutableFactory extends FacetFac
         final Class<?> declaringClass = processMethodContext.getMethod().getDeclaringClass();
         final ObjectSpecification spec = getSpecificationLoader().loadSpecification(
                 declaringClass);
-        if (spec.containsDoOpFacet(ImmutableFacet.class)) {
+        if (spec.containsNonFallbackFacet(ImmutableFacet.class)) {
             final ImmutableFacet immutableFacet = spec.getFacet(ImmutableFacet.class);
             final FacetedMethod facetHolder = processMethodContext.getFacetHolder();
             DisabledFacet facet = facetHolder.getFacet(DisabledFacet.class);
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/properties/disabled/inferred/DisabledFacetOnPropertyInferredFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/properties/disabled/inferred/DisabledFacetOnPropertyInferredFactory.java
index ff4c886..1348699 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/properties/disabled/inferred/DisabledFacetOnPropertyInferredFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/properties/disabled/inferred/DisabledFacetOnPropertyInferredFactory.java
@@ -40,11 +40,11 @@ public class DisabledFacetOnPropertyInferredFactory extends FacetFactoryAbstract
 
         final FacetedMethod property = processMethodContext.getFacetHolder();
 
-        if(property.containsDoOpFacet(DisabledFacet.class)) {
+        if(property.containsNonFallbackFacet(DisabledFacet.class)) {
             // already disabled
             return;
         }
-        if(property.containsDoOpFacet(PropertySetterFacet.class)) {
+        if(property.containsNonFallbackFacet(PropertySetterFacet.class)) {
             // already known to be modifiable
             return;
         }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/properties/propertylayout/PromptStyleFacetForPropertyLayoutAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/properties/propertylayout/PromptStyleFacetForPropertyLayoutAnnotation.java
index b52de10..40bb342 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/properties/propertylayout/PromptStyleFacetForPropertyLayoutAnnotation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/properties/propertylayout/PromptStyleFacetForPropertyLayoutAnnotation.java
@@ -61,7 +61,7 @@ public class PromptStyleFacetForPropertyLayoutAnnotation extends PromptStyleFace
                     case AS_CONFIGURED:
 
                         // do not replace
-                        if (holder.containsDoOpFacet(PromptStyleFacet.class)) {
+                        if (holder.containsNonFallbackFacet(PromptStyleFacet.class)) {
                             return null;
                         }
 
@@ -74,7 +74,7 @@ public class PromptStyleFacetForPropertyLayoutAnnotation extends PromptStyleFace
                 .orElseGet(() -> {
 
                     // do not replace
-                    if (holder.containsDoOpFacet(PromptStyleFacet.class)) {
+                    if (holder.containsNonFallbackFacet(PromptStyleFacet.class)) {
                         return null;
                     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/postprocessors/param/DeriveFacetsPostProcessor.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/postprocessors/param/DeriveFacetsPostProcessor.java
index 7ce5cdb..83d1767 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/postprocessors/param/DeriveFacetsPostProcessor.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/postprocessors/param/DeriveFacetsPostProcessor.java
@@ -373,7 +373,7 @@ implements ObjectSpecificationPostProcessor, MetaModelContextAware {
      * Replaces some of the functionality in {@link DescribedAsFacetOnMemberFactory}.
      */
     private void deriveActionDescribedAsFromType(final ObjectAction objectAction) {
-        if(objectAction.containsDoOpFacet(DescribedAsFacet.class)) {
+        if(objectAction.containsNonFallbackFacet(DescribedAsFacet.class)) {
             return;
         }
         final ObjectSpecification returnSpec = objectAction.getReturnType();
@@ -388,7 +388,7 @@ implements ObjectSpecificationPostProcessor, MetaModelContextAware {
      */
     private void deriveParameterDefaultFacetFromType(final ObjectActionParameter parameter) {
 
-        if (parameter.containsDoOpFacet(ActionDefaultsFacet.class)) {
+        if (parameter.containsNonFallbackFacet(ActionDefaultsFacet.class)) {
             return;
         }
 
@@ -413,7 +413,7 @@ implements ObjectSpecificationPostProcessor, MetaModelContextAware {
      * Replaces {@link ActionParameterChoicesFacetDerivedFromChoicesFacetFactory}.
      */
     private void deriveParameterChoicesFromExistingChoices(final ObjectActionParameter parameter) {
-        if(parameter.containsDoOpFacet(ActionParameterChoicesFacet.class)) {
+        if(parameter.containsNonFallbackFacet(ActionParameterChoicesFacet.class)) {
             return;
         }
         final ObjectSpecification paramSpec = parameter.getSpecification();
@@ -429,7 +429,7 @@ implements ObjectSpecificationPostProcessor, MetaModelContextAware {
      * Replaces {@link DescribedAsFacetOnParameterAnnotationElseDerivedFromTypeFactory}
      */
     private void deriveParameterDescribedAsFromType(final ObjectActionParameter parameter) {
-        if(parameter.containsDoOpFacet(DescribedAsFacet.class)) {
+        if(parameter.containsNonFallbackFacet(DescribedAsFacet.class)) {
             return;
         }
         final ObjectSpecification paramSpec = parameter.getSpecification();
@@ -446,7 +446,7 @@ implements ObjectSpecificationPostProcessor, MetaModelContextAware {
      * Replaces {@link TypicalLengthFacetOnParameterDerivedFromTypeFacetFactory}
      */
     private void deriveParameterTypicalLengthFromType(final ObjectActionParameter parameter) {
-        if(parameter.containsDoOpFacet(TypicalLengthFacet.class)) {
+        if(parameter.containsNonFallbackFacet(TypicalLengthFacet.class)) {
             return;
         }
         final ObjectSpecification paramSpec = parameter.getSpecification();
@@ -460,7 +460,7 @@ implements ObjectSpecificationPostProcessor, MetaModelContextAware {
      * Replaces {@link PropertyChoicesFacetDerivedFromChoicesFacetFactory}
      */
     private void derivePropertyChoicesFromExistingChoices(final OneToOneAssociation property) {
-        if(property.containsDoOpFacet(PropertyChoicesFacet.class)) {
+        if(property.containsNonFallbackFacet(PropertyChoicesFacet.class)) {
             return;
         }
         final ObjectSpecification propertySpec = property.getSpecification();
@@ -475,7 +475,7 @@ implements ObjectSpecificationPostProcessor, MetaModelContextAware {
      * Replaces {@link PropertyDefaultFacetDerivedFromTypeFactory}
      */
     private void derivePropertyDefaultsFromType(final OneToOneAssociation property) {
-        if(property.containsDoOpFacet(PropertyDefaultFacet.class)) {
+        if(property.containsNonFallbackFacet(PropertyDefaultFacet.class)) {
             return;
         }
         final ObjectSpecification propertySpec = property.getSpecification();
@@ -491,7 +491,7 @@ implements ObjectSpecificationPostProcessor, MetaModelContextAware {
      * replaces {@link TypicalLengthFacetOnPropertyDerivedFromTypeFacetFactory}
      */
     private void derivePropertyTypicalLengthFromType(final OneToOneAssociation property) {
-        if(property.containsDoOpFacet(TypicalLengthFacet.class)) {
+        if(property.containsNonFallbackFacet(TypicalLengthFacet.class)) {
             return;
         }
         final ObjectSpecification propertySpec = property.getSpecification();
@@ -506,7 +506,7 @@ implements ObjectSpecificationPostProcessor, MetaModelContextAware {
      * Replaces some of the functionality in {@link DescribedAsFacetOnMemberFactory}.
      */
     private void derivePropertyOrCollectionDescribedAsFromType(final ObjectAssociation objectAssociation) {
-        if(objectAssociation.containsDoOpFacet(DescribedAsFacet.class)) {
+        if(objectAssociation.containsNonFallbackFacet(DescribedAsFacet.class)) {
             return;
         }
         final ObjectSpecification returnSpec = objectAssociation.getSpecification();
@@ -522,7 +522,7 @@ implements ObjectSpecificationPostProcessor, MetaModelContextAware {
      * @param property
      */
     private void derivePropertyDisabledFromViewModel(final OneToOneAssociation property) {
-        if(property.containsDoOpFacet(DisabledFacet.class)){
+        if(property.containsNonFallbackFacet(DisabledFacet.class)){
             return;
         }
 
@@ -539,7 +539,7 @@ implements ObjectSpecificationPostProcessor, MetaModelContextAware {
      * Replaces {@link DisabledFacetOnPropertyDerivedFromImmutableFactory}
      */
     private void derivePropertyDisabledFromImmutable(final OneToOneAssociation property) {
-        if(property.containsDoOpFacet(DisabledFacet.class)) {
+        if(property.containsNonFallbackFacet(DisabledFacet.class)) {
             return;
         }
         final ObjectSpecification onType = property.getOnType();
@@ -555,7 +555,7 @@ implements ObjectSpecificationPostProcessor, MetaModelContextAware {
      * @param collection
      */
     private void deriveCollectionDisabledFromViewModel(final OneToManyAssociation collection) {
-        if(collection.containsDoOpFacet(DisabledFacet.class)){
+        if(collection.containsNonFallbackFacet(DisabledFacet.class)){
             return;
         }
 
@@ -572,7 +572,7 @@ implements ObjectSpecificationPostProcessor, MetaModelContextAware {
      * Replaces {@link DisabledFacetOnCollectionDerivedFromImmutableFactory}
      */
     private void deriveCollectionDisabledFromImmutable(final OneToManyAssociation collection) {
-        if(collection.containsDoOpFacet(DisabledFacet.class)) {
+        if(collection.containsNonFallbackFacet(DisabledFacet.class)) {
             return;
         }
         final ObjectSpecification onType = collection.getOnType();
@@ -586,7 +586,7 @@ implements ObjectSpecificationPostProcessor, MetaModelContextAware {
 
 
     private void addCollectionParamDefaultsFacetIfNoneAlready(final ObjectActionParameter collectionParam) {
-        if(collectionParam.containsDoOpFacet(ActionParameterDefaultsFacet.class)) {
+        if(collectionParam.containsNonFallbackFacet(ActionParameterDefaultsFacet.class)) {
             return;
         }
         this.addFacet(new ActionParameterDefaultsFacetFromAssociatedCollection(collectionParam));
@@ -595,8 +595,8 @@ implements ObjectSpecificationPostProcessor, MetaModelContextAware {
     private void addCollectionParamChoicesFacetIfNoneAlready(
             final OneToManyAssociation otma,
             final ObjectActionParameter scalarOrCollectionParam) {
-        if (scalarOrCollectionParam.containsDoOpFacet(ActionParameterChoicesFacet.class) ||
-                scalarOrCollectionParam.containsDoOpFacet(ActionParameterAutoCompleteFacet.class)) {
+        if (scalarOrCollectionParam.containsNonFallbackFacet(ActionParameterChoicesFacet.class) ||
+                scalarOrCollectionParam.containsNonFallbackFacet(ActionParameterAutoCompleteFacet.class)) {
             return;
         }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/services/appfeat/ApplicationFeatureRepositoryDefault.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/services/appfeat/ApplicationFeatureRepositoryDefault.java
index 606495c..495f5ca 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/services/appfeat/ApplicationFeatureRepositoryDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/services/appfeat/ApplicationFeatureRepositoryDefault.java
@@ -153,12 +153,12 @@ public class ApplicationFeatureRepositoryDefault implements ApplicationFeatureRe
             final Class<?> returnType = correspondingClassFor(property.getSpecification());
             final Integer maxLength = returnType == String.class ? valueOf(property, MaxLengthFacet.class) : null;
             final Integer typicalLength = returnType == String.class ? valueOf(property, TypicalLengthFacet.class) : null;
-            final boolean derived = !property.containsDoOpFacet(PropertySetterFacet.class);
+            final boolean derived = !property.containsNonFallbackFacet(PropertySetterFacet.class);
             final boolean contributed = property instanceof ContributeeMember;
             addedMembers = newProperty(classFeatureId, property, returnType, contributed, maxLength, typicalLength, derived) || addedMembers;
         }
         for (final ObjectAssociation collection : collections) {
-            final boolean derived = !(collection.containsDoOpFacet(CollectionAddToFacet.class) || collection.containsDoOpFacet(CollectionRemoveFromFacet.class));
+            final boolean derived = !(collection.containsNonFallbackFacet(CollectionAddToFacet.class) || collection.containsNonFallbackFacet(CollectionRemoveFromFacet.class));
             final Class<?> elementType = correspondingClassFor(collection.getSpecification());
             final boolean contributed = collection instanceof ContributeeMember;
             addedMembers = newCollection(classFeatureId, collection, elementType, contributed, derived) || addedMembers;
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/services/registry/ServiceRegistryDefault.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/services/registry/ServiceRegistryDefault.java
index bb716ec..524749e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/services/registry/ServiceRegistryDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/services/registry/ServiceRegistryDefault.java
@@ -29,7 +29,7 @@ import javax.inject.Inject;
 import org.apache.isis.applib.annotation.DomainService;
 import org.apache.isis.applib.annotation.NatureOfService;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
-import org.apache.isis.commons.collections.Bin;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._Lazy;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.collections._Maps;
@@ -60,7 +60,7 @@ public final class ServiceRegistryDefault implements ServiceRegistry {
     }
     
     @Override
-    public <T> Bin<T> select(Class<T> type, Annotation[] qualifiers) {
+    public <T> Can<T> select(Class<T> type, Annotation[] qualifiers) {
         return isisSystemEnvironment.getIocContainer()
                 .select(type, _Spring.filterQualifiers(qualifiers));
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/spec/feature/ObjectAssociation.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/spec/feature/ObjectAssociation.java
index 0702ba7..499cebe 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/spec/feature/ObjectAssociation.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/spec/feature/ObjectAssociation.java
@@ -149,7 +149,7 @@ public interface ObjectAssociation extends ObjectMember, CurrentHolder {
             @Override
             public boolean test(final ObjectAssociation association) {
                 return association.isOneToOneAssociation() &&
-                        !association.getSpecification().containsDoOpFacet(ValueFacet.class);
+                        !association.getSpecification().containsNonFallbackFacet(ValueFacet.class);
             }
         };
         public final static Predicate<ObjectAssociation> COLLECTIONS = new Predicate<ObjectAssociation>() {
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/SpecificationCacheDefault.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/SpecificationCacheDefault.java
index 7e3ee1a..94bc96c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/SpecificationCacheDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/specloader/SpecificationCacheDefault.java
@@ -123,7 +123,7 @@ class SpecificationCacheDefault<T extends ObjectSpecification> {
     private boolean hasUsableSpecId(T spec) {
         // umm.  It turns out that anonymous inner classes (eg org.estatio.dom.WithTitleGetter$ToString$1)
         // don't have an ObjectSpecId; hence the guard.
-        return spec!=null && spec.containsDoOpFacet(ObjectSpecIdFacet.class);
+        return spec!=null && spec.containsNonFallbackFacet(ObjectSpecIdFacet.class);
     }
 
 }
diff --git a/core/metamodel/src/test/java/org/apache/isis/metamodel/ServiceRegistry_forTesting.java b/core/metamodel/src/test/java/org/apache/isis/metamodel/ServiceRegistry_forTesting.java
index d2c90d0..70ed9b1 100644
--- a/core/metamodel/src/test/java/org/apache/isis/metamodel/ServiceRegistry_forTesting.java
+++ b/core/metamodel/src/test/java/org/apache/isis/metamodel/ServiceRegistry_forTesting.java
@@ -24,7 +24,7 @@ import java.util.Set;
 import java.util.stream.Stream;
 
 import org.apache.isis.applib.services.registry.ServiceRegistry;
-import org.apache.isis.commons.collections.Bin;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.collections._Sets;
@@ -52,7 +52,7 @@ class ServiceRegistry_forTesting implements ServiceRegistry {
     private final Set<ManagedBeanAdapter> registeredBeans = _Sets.newHashSet();
 
     @Override
-    public <T> Bin<T> select(Class<T> type, Annotation[] qualifiers) {
+    public <T> Can<T> select(Class<T> type, Annotation[] qualifiers) {
 
         if(iocContainer!=null) {
             return iocContainer
@@ -70,17 +70,17 @@ class ServiceRegistry_forTesting implements ServiceRegistry {
                 .findFirst();
 
         if(match.isPresent()) {
-            return Bin.ofSingleton(match.get());
+            return Can.ofSingleton(match.get());
         }
 
         // lookup the _Context 
         // XXX lombok bug, cannot use val here (https://github.com/rzwitserloot/lombok/issues/1588)
         T singleton = _Context.getIfAny(type);
         if(singleton!=null) {
-            return Bin.ofSingleton(singleton);
+            return Can.ofSingleton(singleton);
         }
 
-        return Bin.empty();
+        return Can.empty();
     }
 
     @Override
@@ -125,7 +125,7 @@ class ServiceRegistry_forTesting implements ServiceRegistry {
     private static class PojoBeanAdapter implements ManagedBeanAdapter {
 
         String id;
-        Bin<?> instance;
+        Can<?> instance;
         public Class<?> beanClass;
 
         @Override
@@ -139,7 +139,7 @@ class ServiceRegistry_forTesting implements ServiceRegistry {
 
         return PojoBeanAdapter.builder()
                 .id(singleton.getClass().getName())
-                .instance(Bin.ofSingleton(singleton))
+                .instance(Can.ofSingleton(singleton))
                 .beanClass(singleton.getClass())
                 .build();
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/Annotations_getAnnotations_on_Field_Test.java b/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/Annotations_getAnnotations_on_Field_Test.java
index 177cfc7..4376853 100644
--- a/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/Annotations_getAnnotations_on_Field_Test.java
+++ b/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/Annotations_getAnnotations_on_Field_Test.java
@@ -23,16 +23,12 @@ import java.lang.annotation.Inherited;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-import java.lang.reflect.Method;
-import java.util.List;
 
-import org.junit.Assert;
 import org.junit.Test;
 
 import org.apache.isis.applib.annotation.Property;
 import org.apache.isis.applib.annotation.Publishing;
 import org.apache.isis.commons.internal.reflection._Annotations;
-import org.apache.isis.metamodel.facets.Annotations_getAnnotations_on_Parameter_Test.DomainObj;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertThat;
diff --git a/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/Annotations_getAnnotations_on_Parameter_Test.java b/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/Annotations_getAnnotations_on_Parameter_Test.java
index 9f5fe88..40c11b0 100644
--- a/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/Annotations_getAnnotations_on_Parameter_Test.java
+++ b/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/Annotations_getAnnotations_on_Parameter_Test.java
@@ -23,14 +23,10 @@ import java.lang.annotation.Inherited;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-import java.lang.reflect.Method;
-import java.util.List;
 
-import org.junit.Assert;
 import org.junit.Test;
 
 import org.apache.isis.commons.internal.reflection._Annotations;
-import org.apache.isis.metamodel.facets.Annotations_getAnnotations_on_Method_Test.DomainObj;
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.junit.Assert.assertThat;
diff --git a/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/actions/action/ActionAnnotationFacetFactoryTest_ActionInvocation.java b/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/actions/action/ActionAnnotationFacetFactoryTest_ActionInvocation.java
index d807bd6..897ade8 100644
--- a/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/actions/action/ActionAnnotationFacetFactoryTest_ActionInvocation.java
+++ b/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/actions/action/ActionAnnotationFacetFactoryTest_ActionInvocation.java
@@ -22,7 +22,6 @@ package org.apache.isis.metamodel.facets.actions.action;
 import java.lang.reflect.Method;
 
 import org.apache.isis.applib.annotation.Action;
-import org.apache.isis.metamodel.MetaModelContext_forTesting;
 import org.apache.isis.metamodel.facetapi.Facet;
 import org.apache.isis.metamodel.facets.AbstractFacetFactoryTest;
 import org.apache.isis.metamodel.facets.FacetFactory.ProcessMethodContext;
diff --git a/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/actions/action/ActionAnnotationFacetFactoryTest_Invocation.java b/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/actions/action/ActionAnnotationFacetFactoryTest_Invocation.java
index f6acc0b..6199696 100644
--- a/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/actions/action/ActionAnnotationFacetFactoryTest_Invocation.java
+++ b/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/actions/action/ActionAnnotationFacetFactoryTest_Invocation.java
@@ -32,7 +32,6 @@ import org.apache.isis.metamodel.facets.actions.action.invocation.ActionDomainEv
 import org.apache.isis.metamodel.facets.actions.action.invocation.ActionInvocationFacet;
 import org.apache.isis.metamodel.facets.actions.action.invocation.ActionInvocationFacetForDomainEventFromActionAnnotation;
 import org.apache.isis.metamodel.facets.actions.action.invocation.ActionInvocationFacetForDomainEventFromDefault;
-import org.apache.isis.unittestsupport.config.internal._Config;
 
 import static org.apache.isis.metamodel.commons.matchers.IsisMatchers.classEqualTo;
 import static org.junit.Assert.assertThat;
diff --git a/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/object/value/ValueFacetAnnotationOrConfigurationFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/object/value/ValueFacetAnnotationOrConfigurationFactoryTest.java
index 848ac94..54d3e1a 100644
--- a/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/object/value/ValueFacetAnnotationOrConfigurationFactoryTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/object/value/ValueFacetAnnotationOrConfigurationFactoryTest.java
@@ -36,12 +36,9 @@ import org.apache.isis.metamodel.facets.object.value.annotcfg.ValueFacetAnnotati
 import org.apache.isis.metamodel.facets.object.value.vsp.ValueSemanticsProviderUtil;
 import org.apache.isis.metamodel.facets.objectvalue.typicallen.TypicalLengthFacet;
 import org.apache.isis.unittestsupport.config.internal._Config;
-import org.apache.isis.unittestsupport.jmocking.JUnitRuleMockery2;
 
 public class ValueFacetAnnotationOrConfigurationFactoryTest extends AbstractFacetFactoryTest {
 
-    private JUnitRuleMockery2 context = JUnitRuleMockery2.createFor(JUnitRuleMockery2.Mode.INTERFACES_AND_CLASSES);
-
     private ValueFacetAnnotationOrConfigurationFactory facetFactory;
 
     @Override
diff --git a/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/properties/promptstyle/PromptStyleFacetFromPropertyAnnotation_Test.java b/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/properties/promptstyle/PromptStyleFacetFromPropertyAnnotation_Test.java
index 672907d..134fb90 100644
--- a/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/properties/promptstyle/PromptStyleFacetFromPropertyAnnotation_Test.java
+++ b/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/properties/promptstyle/PromptStyleFacetFromPropertyAnnotation_Test.java
@@ -99,7 +99,7 @@ public class PromptStyleFacetFromPropertyAnnotation_Test {
                 allowing(mockPropertyLayout).promptStyle();
                 will(returnValue(PromptStyle.AS_CONFIGURED));
 
-                allowing(mockFacetHolder).containsDoOpFacet(PromptStyleFacet.class);
+                allowing(mockFacetHolder).containsNonFallbackFacet(PromptStyleFacet.class);
                 will(returnValue(false));
             }});
 
@@ -117,7 +117,7 @@ public class PromptStyleFacetFromPropertyAnnotation_Test {
                 allowing(mockPropertyLayout).promptStyle();
                 will(returnValue(PromptStyle.AS_CONFIGURED));
 
-                allowing(mockFacetHolder).containsDoOpFacet(PromptStyleFacet.class);
+                allowing(mockFacetHolder).containsNonFallbackFacet(PromptStyleFacet.class);
                 will(returnValue(true));
 
             }});
@@ -135,7 +135,7 @@ public class PromptStyleFacetFromPropertyAnnotation_Test {
                 allowing(mockPropertyLayout).promptStyle();
                 will(returnValue(PromptStyle.NOT_SPECIFIED));
 
-                allowing(mockFacetHolder).containsDoOpFacet(PromptStyleFacet.class);
+                allowing(mockFacetHolder).containsNonFallbackFacet(PromptStyleFacet.class);
                 will(returnValue(false));
             }});
 
@@ -153,7 +153,7 @@ public class PromptStyleFacetFromPropertyAnnotation_Test {
                 allowing(mockPropertyLayout).promptStyle();
                 will(returnValue(PromptStyle.NOT_SPECIFIED));
 
-                allowing(mockFacetHolder).containsDoOpFacet(PromptStyleFacet.class);
+                allowing(mockFacetHolder).containsNonFallbackFacet(PromptStyleFacet.class);
                 will(returnValue(true));
 
             }});
diff --git a/core/metamodel/src/test/java/org/apache/isis/metamodel/specloader/specimpl/ObjectAssociationAbstractTest.java b/core/metamodel/src/test/java/org/apache/isis/metamodel/specloader/specimpl/ObjectAssociationAbstractTest.java
index 994c9e0..32f0e50 100644
--- a/core/metamodel/src/test/java/org/apache/isis/metamodel/specloader/specimpl/ObjectAssociationAbstractTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/metamodel/specloader/specimpl/ObjectAssociationAbstractTest.java
@@ -131,7 +131,7 @@ public class ObjectAssociationAbstractTest {
             }
 
             @Override
-            public boolean containsDoOpFacet(final Class<? extends Facet> facetType) {
+            public boolean containsNonFallbackFacet(final Class<? extends Facet> facetType) {
                 return false;
             }
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/metamodel/specloader/specimpl/ObjectAssociationAbstractTest_alwaysHidden.java b/core/metamodel/src/test/java/org/apache/isis/metamodel/specloader/specimpl/ObjectAssociationAbstractTest_alwaysHidden.java
index 56a7587..160a1b7 100644
--- a/core/metamodel/src/test/java/org/apache/isis/metamodel/specloader/specimpl/ObjectAssociationAbstractTest_alwaysHidden.java
+++ b/core/metamodel/src/test/java/org/apache/isis/metamodel/specloader/specimpl/ObjectAssociationAbstractTest_alwaysHidden.java
@@ -133,7 +133,7 @@ public class ObjectAssociationAbstractTest_alwaysHidden {
             }
 
             @Override
-            public boolean containsDoOpFacet(final Class<? extends Facet> facetType) {
+            public boolean containsNonFallbackFacet(final Class<? extends Facet> facetType) {
                 return false;
             }
 
diff --git a/core/plugins/jdo/common/src/main/java/org/apache/isis/jdo/metamodel/JdoProgrammingModelPlugin.java b/core/plugins/jdo/common/src/main/java/org/apache/isis/jdo/metamodel/JdoProgrammingModelPlugin.java
index 7c07178..811e2d7 100644
--- a/core/plugins/jdo/common/src/main/java/org/apache/isis/jdo/metamodel/JdoProgrammingModelPlugin.java
+++ b/core/plugins/jdo/common/src/main/java/org/apache/isis/jdo/metamodel/JdoProgrammingModelPlugin.java
@@ -158,7 +158,7 @@ public class JdoProgrammingModelPlugin implements MetaModelRefiner {
     private void addValidatorToCheckForUnsupportedAnnotations() {
 
         pm.addValidator((objSpec, validation) -> {
-            if (objSpec.containsDoOpFacet(ParentedCollectionFacet.class) && !objSpec.containsDoOpFacet(CollectionFacet.class)) {
+            if (objSpec.containsNonFallbackFacet(ParentedCollectionFacet.class) && !objSpec.containsNonFallbackFacet(CollectionFacet.class)) {
                 validation.onFailure(
                         objSpec,
                         objSpec.getIdentifier(),
diff --git a/core/plugins/jdo/common/src/main/java/org/apache/isis/jdo/metamodel/facets/object/persistencecapable/JdoPersistenceCapableFacetAbstract.java b/core/plugins/jdo/common/src/main/java/org/apache/isis/jdo/metamodel/facets/object/persistencecapable/JdoPersistenceCapableFacetAbstract.java
index 72dcd6a..3dd58cf 100644
--- a/core/plugins/jdo/common/src/main/java/org/apache/isis/jdo/metamodel/facets/object/persistencecapable/JdoPersistenceCapableFacetAbstract.java
+++ b/core/plugins/jdo/common/src/main/java/org/apache/isis/jdo/metamodel/facets/object/persistencecapable/JdoPersistenceCapableFacetAbstract.java
@@ -46,10 +46,10 @@ implements JdoPersistenceCapableFacet {
             final IdentityType identityType,
             final FacetHolder holder) {
         super(JdoPersistenceCapableFacetAbstract.type(), holder, Derivation.NOT_DERIVED);
+        super.setFacetAliasType(EntityFacet.class);
         this.schema = schemaName;
         this.table = tableOrTypeName;
         this.identityType = identityType;
-        super.addAlias(EntityFacet.class);
     }
 
     @Override
diff --git a/core/plugins/jdo/common/src/main/java/org/apache/isis/jdo/metamodel/facets/prop/column/BigDecimalDerivedFromJdoColumnAnnotationFacetFactory.java b/core/plugins/jdo/common/src/main/java/org/apache/isis/jdo/metamodel/facets/prop/column/BigDecimalDerivedFromJdoColumnAnnotationFacetFactory.java
index d3dd0e3..277e5d2 100644
--- a/core/plugins/jdo/common/src/main/java/org/apache/isis/jdo/metamodel/facets/prop/column/BigDecimalDerivedFromJdoColumnAnnotationFacetFactory.java
+++ b/core/plugins/jdo/common/src/main/java/org/apache/isis/jdo/metamodel/facets/prop/column/BigDecimalDerivedFromJdoColumnAnnotationFacetFactory.java
@@ -129,7 +129,7 @@ implements MetaModelRefiner {
 
                 associations
                 // skip checks if annotated with JDO @NotPersistent
-                .filter(association->!association.containsDoOpFacet(JdoNotPersistentFacet.class))
+                .filter(association->!association.containsNonFallbackFacet(JdoNotPersistentFacet.class))
                 .forEach(association->{
                     validateBigDecimalValueFacet(association, validator);
                 });
diff --git a/core/plugins/jdo/common/src/main/java/org/apache/isis/jdo/metamodel/facets/prop/column/MandatoryFromJdoColumnAnnotationFacetFactory.java b/core/plugins/jdo/common/src/main/java/org/apache/isis/jdo/metamodel/facets/prop/column/MandatoryFromJdoColumnAnnotationFacetFactory.java
index 718f865..c833998 100644
--- a/core/plugins/jdo/common/src/main/java/org/apache/isis/jdo/metamodel/facets/prop/column/MandatoryFromJdoColumnAnnotationFacetFactory.java
+++ b/core/plugins/jdo/common/src/main/java/org/apache/isis/jdo/metamodel/facets/prop/column/MandatoryFromJdoColumnAnnotationFacetFactory.java
@@ -140,7 +140,7 @@ implements MetaModelRefiner {
 
                 associations
                 // skip checks if annotated with JDO @NotPersistent
-                .filter(association->!association.containsDoOpFacet(JdoNotPersistentFacet.class))
+                .filter(association->!association.containsNonFallbackFacet(JdoNotPersistentFacet.class))
                 .forEach(association->validateMandatoryFacet(association, validator));
             }
 
diff --git a/core/plugins/jdo/common/src/main/java/org/apache/isis/jdo/metamodel/facets/prop/column/MaxLengthDerivedFromJdoColumnAnnotationFacetFactory.java b/core/plugins/jdo/common/src/main/java/org/apache/isis/jdo/metamodel/facets/prop/column/MaxLengthDerivedFromJdoColumnAnnotationFacetFactory.java
index 6540504..e83b4e9 100644
--- a/core/plugins/jdo/common/src/main/java/org/apache/isis/jdo/metamodel/facets/prop/column/MaxLengthDerivedFromJdoColumnAnnotationFacetFactory.java
+++ b/core/plugins/jdo/common/src/main/java/org/apache/isis/jdo/metamodel/facets/prop/column/MaxLengthDerivedFromJdoColumnAnnotationFacetFactory.java
@@ -115,7 +115,7 @@ implements MetaModelRefiner {
 
                 associations.forEach(association->{
                     // skip checks if annotated with JDO @NotPersistent
-                    if(association.containsDoOpFacet(JdoNotPersistentFacet.class)) {
+                    if(association.containsNonFallbackFacet(JdoNotPersistentFacet.class)) {
                         return;
                     }
 
diff --git a/core/runtime-services/src/main/java/org/apache/isis/runtime/services/homepage/HomePageResolverServiceDefault.java b/core/runtime-services/src/main/java/org/apache/isis/runtime/services/homepage/HomePageResolverServiceDefault.java
index 1f65281..2d130df 100644
--- a/core/runtime-services/src/main/java/org/apache/isis/runtime/services/homepage/HomePageResolverServiceDefault.java
+++ b/core/runtime-services/src/main/java/org/apache/isis/runtime/services/homepage/HomePageResolverServiceDefault.java
@@ -150,7 +150,7 @@ public class HomePageResolverServiceDefault implements HomePageResolverService {
 
     protected HomePageAction homePageActionIfUsable(ObjectAction objectAction, ObjectSpecification spec) {
 
-        if (!objectAction.containsDoOpFacet(HomePageFacet.class)) {
+        if (!objectAction.containsNonFallbackFacet(HomePageFacet.class)) {
             return null;
         }
 
diff --git a/core/runtime-services/src/main/java/org/apache/isis/runtime/services/i18n/po/PoReader.java b/core/runtime-services/src/main/java/org/apache/isis/runtime/services/i18n/po/PoReader.java
index 9f04bcf..4e06008 100644
--- a/core/runtime-services/src/main/java/org/apache/isis/runtime/services/i18n/po/PoReader.java
+++ b/core/runtime-services/src/main/java/org/apache/isis/runtime/services/i18n/po/PoReader.java
@@ -28,7 +28,7 @@ import java.util.stream.Collectors;
 import org.apache.isis.applib.services.i18n.LocaleProvider;
 import org.apache.isis.applib.services.i18n.TranslationService;
 import org.apache.isis.applib.services.i18n.TranslationsResolver;
-import org.apache.isis.commons.collections.Bin;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._Strings;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.commons.internal.collections._Maps;
@@ -60,8 +60,8 @@ class PoReader extends PoAbstract {
      * </p>
      */
     private final String basename = "translations";
-    private final Bin<TranslationsResolver> translationsResolver;
-    private final Bin<LocaleProvider> localeProvider;
+    private final Can<TranslationsResolver> translationsResolver;
+    private final Can<LocaleProvider> localeProvider;
 
     private List<String> fallback;
 
diff --git a/core/runtime-services/src/main/java/org/apache/isis/runtime/services/i18n/po/TranslationServicePo.java b/core/runtime-services/src/main/java/org/apache/isis/runtime/services/i18n/po/TranslationServicePo.java
index 5db2b50..4942519 100644
--- a/core/runtime-services/src/main/java/org/apache/isis/runtime/services/i18n/po/TranslationServicePo.java
+++ b/core/runtime-services/src/main/java/org/apache/isis/runtime/services/i18n/po/TranslationServicePo.java
@@ -28,7 +28,7 @@ import org.apache.isis.applib.services.i18n.LocaleProvider;
 import org.apache.isis.applib.services.i18n.TranslationService;
 import org.apache.isis.applib.services.i18n.TranslationsResolver;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
-import org.apache.isis.commons.collections.Bin;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._Lazy;
 import org.apache.isis.commons.internal.context._Context;
 import org.apache.isis.commons.internal.environment.IsisSystemEnvironment;
@@ -164,17 +164,17 @@ public class TranslationServicePo implements TranslationService {
     @Inject private IsisSystemEnvironment isisSystemEnvironment;
     @Inject private ServiceRegistry serviceRegistry;
     
-    private _Lazy<Bin<TranslationsResolver>> translationsResolvers = _Lazy.threadSafe(()->
+    private _Lazy<Can<TranslationsResolver>> translationsResolvers = _Lazy.threadSafe(()->
     serviceRegistry.select(TranslationsResolver.class) );
 
-    Bin<TranslationsResolver> getTranslationsResolver() {
+    Can<TranslationsResolver> getTranslationsResolver() {
         return translationsResolvers.get();
     }
 
-    private _Lazy<Bin<LocaleProvider>> localeProviders = _Lazy.threadSafe(()->
+    private _Lazy<Can<LocaleProvider>> localeProviders = _Lazy.threadSafe(()->
     serviceRegistry.select(LocaleProvider.class) );
 
-    Bin<LocaleProvider> getLocaleProvider() {
+    Can<LocaleProvider> getLocaleProvider() {
         return localeProviders.get();
     }
 
diff --git a/core/runtime-services/src/test/java/org/apache/isis/runtime/services/i18n/po/PoReaderTest.java b/core/runtime-services/src/test/java/org/apache/isis/runtime/services/i18n/po/PoReaderTest.java
index 08929b6..5961de4 100644
--- a/core/runtime-services/src/test/java/org/apache/isis/runtime/services/i18n/po/PoReaderTest.java
+++ b/core/runtime-services/src/test/java/org/apache/isis/runtime/services/i18n/po/PoReaderTest.java
@@ -30,7 +30,7 @@ import org.junit.Test;
 
 import org.apache.isis.applib.services.i18n.LocaleProvider;
 import org.apache.isis.applib.services.i18n.TranslationsResolver;
-import org.apache.isis.commons.collections.Bin;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.unittestsupport.jmocking.JUnitRuleMockery2;
 
@@ -54,10 +54,10 @@ public class PoReaderTest {
 
         context.checking(new Expectations() {{
             allowing(mockTranslationServicePo).getLocaleProvider();
-            will(returnValue(Bin.ofSingleton(mockLocaleProvider)));
+            will(returnValue(Can.ofSingleton(mockLocaleProvider)));
 
             allowing(mockTranslationServicePo).getTranslationsResolver();
-            will(returnValue(Bin.ofSingleton(mockTranslationsResolver)));
+            will(returnValue(Can.ofSingleton(mockTranslationsResolver)));
 
             allowing(mockLocaleProvider).getLocale();
             will(returnValue(Locale.UK));
diff --git a/core/runtime/src/main/java/org/apache/isis/runtime/system/persistence/PersistenceSession.java b/core/runtime/src/main/java/org/apache/isis/runtime/system/persistence/PersistenceSession.java
index f5be0b4..7296252 100644
--- a/core/runtime/src/main/java/org/apache/isis/runtime/system/persistence/PersistenceSession.java
+++ b/core/runtime/src/main/java/org/apache/isis/runtime/system/persistence/PersistenceSession.java
@@ -26,7 +26,7 @@ import javax.jdo.PersistenceManager;
 import org.apache.isis.applib.query.Query;
 import org.apache.isis.applib.services.inject.ServiceInjector;
 import org.apache.isis.applib.services.xactn.TransactionService;
-import org.apache.isis.commons.collections.Bin;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.components.SessionScopedComponent;
 import org.apache.isis.commons.internal.context._Context;
 import org.apache.isis.metamodel.adapter.ObjectAdapter;
@@ -163,7 +163,7 @@ SessionScopedComponent {
 
     // -- LOOKUP
 
-    static <T extends PersistenceSession> Bin<T> current(Class<T> requiredType) {
+    static <T extends PersistenceSession> Can<T> current(Class<T> requiredType) {
         return _Context.threadLocalSelect(PersistenceSession.class, requiredType);
     }
 
diff --git a/core/viewer-wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java b/core/viewer-wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
index 2807d36..0fe2221 100644
--- a/core/viewer-wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
+++ b/core/viewer-wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityCollectionModel.java
@@ -31,6 +31,7 @@ import java.util.stream.Stream;
 import org.apache.wicket.Component;
 
 import org.apache.isis.applib.layout.component.CollectionLayoutData;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._Casts;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.collections._Lists;
@@ -536,8 +537,8 @@ implements LinksProvider, UiHintContainer {
         }
     }
 
-    public List<ObjectAdapterMemento> getToggleMementosList() {
-        return Collections.unmodifiableList(_Lists.newArrayList(this.toggledMementosList));
+    public Can<ObjectAdapterMemento> getToggleMementosList() {
+        return Can.ofCollection(this.toggledMementosList);
     }
 
     public void clearToggleMementosList() {
diff --git a/core/viewer-wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ToggledMementosProvider.java b/core/viewer-wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ToggledMementosProvider.java
index 4cce556..3ab984c 100644
--- a/core/viewer-wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ToggledMementosProvider.java
+++ b/core/viewer-wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ToggledMementosProvider.java
@@ -19,13 +19,14 @@
 package org.apache.isis.viewer.wicket.model.models;
 
 import java.io.Serializable;
-import java.util.List;
 
 import org.apache.wicket.ajax.AjaxRequestTarget;
 
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.runtime.memento.ObjectAdapterMemento;
 
 public interface ToggledMementosProvider extends Serializable {
-    List<ObjectAdapterMemento> getToggles();
+    
+    Can<ObjectAdapterMemento> getToggles();
     void clearToggles(final AjaxRequestTarget target);
 }
diff --git a/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/LinkAndLabelUtil.java b/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/LinkAndLabelUtil.java
index 9b6da0b..a818431 100644
--- a/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/LinkAndLabelUtil.java
+++ b/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actionmenu/entityactions/LinkAndLabelUtil.java
@@ -20,9 +20,9 @@ package org.apache.isis.viewer.wicket.ui.components.actionmenu.entityactions;
 
 import java.util.Collections;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import org.apache.isis.commons.internal.base._NullSafe;
-import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
@@ -75,11 +75,12 @@ public final class LinkAndLabelUtil {
 
         final ActionLinkFactory linkFactory = new EntityActionLinkFactory(parentEntityModel, scalarModelIfAny);
 
-        return _Lists.transform(objectActions, stream -> stream
+        return _NullSafe.stream(objectActions)
                 .map((ObjectAction objectAction) ->
-                linkFactory.newLink(
+                    linkFactory.newLink(
                         objectAction, AdditionalLinksPanel.ID_ADDITIONAL_LINK, toggledMementosProviderIfAny))
-                .filter(_NullSafe::isPresent));
+                .filter(_NullSafe::isPresent)
+                .collect(Collectors.toList());
     }
 
 }
diff --git a/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanel.java b/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanel.java
index 4b90dca..749c5b1 100644
--- a/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanel.java
+++ b/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collection/CollectionPanel.java
@@ -27,6 +27,7 @@ import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.feedback.ComponentFeedbackMessageFilter;
 import org.apache.wicket.markup.html.basic.Label;
 
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.metamodel.spec.ManagedObject;
 import org.apache.isis.metamodel.spec.feature.ObjectAction;
@@ -186,7 +187,7 @@ implements CollectionSelectorProvider, BulkActionsProvider {
         }
 
         @Override
-        public List<ObjectAdapterMemento> getToggles() {
+        public Can<ObjectAdapterMemento> getToggles() {
             return collectionModel.getToggleMementosList();
         }
 
diff --git a/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java b/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
index 3b35ae9..a87a35d 100644
--- a/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
+++ b/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/ajaxtable/CollectionContentsAsAjaxTablePanel.java
@@ -35,7 +35,7 @@ import org.apache.wicket.model.Model;
 import org.apache.isis.applib.annotation.Where;
 import org.apache.isis.applib.layout.grid.Grid;
 import org.apache.isis.applib.services.tablecol.TableColumnOrderService;
-import org.apache.isis.commons.collections.Bin;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.commons.internal.collections._Maps;
 import org.apache.isis.metamodel.adapter.ObjectAdapter;
@@ -249,7 +249,7 @@ implements CollectionCountProvider {
                 }
 
                 // optional SPI to reorder
-                final Bin<TableColumnOrderService> tableColumnOrderServices =
+                final Can<TableColumnOrderService> tableColumnOrderServices =
                         getServiceRegistry().select(TableColumnOrderService.class);
 
                 for (final TableColumnOrderService tableColumnOrderService : tableColumnOrderServices) {
diff --git a/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/summary/CollectionContentsAsSummaryFactory.java b/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/summary/CollectionContentsAsSummaryFactory.java
index 273b724..579c729 100644
--- a/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/summary/CollectionContentsAsSummaryFactory.java
+++ b/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/collectioncontents/summary/CollectionContentsAsSummaryFactory.java
@@ -49,7 +49,7 @@ public class CollectionContentsAsSummaryFactory extends ComponentFactoryAbstract
 
     final static Predicate<ObjectAssociation> OF_TYPE_BIGDECIMAL = (final ObjectAssociation objectAssoc) -> {
         final ObjectSpecification objectSpec = objectAssoc.getSpecification();
-        return objectSpec.containsDoOpFacet(BigDecimalValueFacet.class);
+        return objectSpec.containsNonFallbackFacet(BigDecimalValueFacet.class);
     };
 
     // //////////////////////////////////////
diff --git a/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/bs3/col/Col.java b/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/bs3/col/Col.java
index 4e6ca90..459eb56 100644
--- a/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/bs3/col/Col.java
+++ b/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/layout/bs3/col/Col.java
@@ -37,7 +37,6 @@ import org.apache.isis.applib.layout.grid.bootstrap3.BS3Tab;
 import org.apache.isis.applib.layout.grid.bootstrap3.BS3TabGroup;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.collections._Lists;
-import org.apache.isis.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.isis.viewer.wicket.ui.ComponentFactory;
@@ -53,6 +52,8 @@ import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
 import org.apache.isis.viewer.wicket.ui.util.Components;
 import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
 
+import lombok.val;
+
 public class Col extends PanelAbstract<EntityModel> implements HasDynamicallyVisibleContent {
 
     private static final long serialVersionUID = 1L;
@@ -121,14 +122,15 @@ public class Col extends PanelAbstract<EntityModel> implements HasDynamicallyVis
         // actions
         // (rendering depends on whether also showing the icon/title)
         final List<ActionLayoutData> actionLayoutDatas = bs3Col.getActions();
-        final List<ObjectAction> visibleActions = _Lists.transform(actionLayoutDatas, stream->stream
+        val visibleActions = _NullSafe.stream(actionLayoutDatas)
                 .filter((final ActionLayoutData actionLayoutData) -> {
                     return actionLayoutData.getMetadataError() == null;
                 })
                 .map((@Nullable final ActionLayoutData actionLayoutData) -> {
                     return getModel().getTypeOfSpecification().getObjectAction(actionLayoutData.getId());
                 })
-                .filter(_NullSafe::isPresent));
+                .filter(_NullSafe::isPresent)
+                .collect(Collectors.toList());
         //
         // visibility needs to be determined at point of rendering, by ActionLink itself
         //
diff --git a/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/ActionLinkFactoryAbstract.java b/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/ActionLinkFactoryAbstract.java
index 795e3d8..90304fd 100644
--- a/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/ActionLinkFactoryAbstract.java
+++ b/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/widgets/linkandlabel/ActionLinkFactoryAbstract.java
@@ -18,6 +18,7 @@
 package org.apache.isis.viewer.wicket.ui.components.widgets.linkandlabel;
 
 import java.util.List;
+import java.util.stream.Collectors;
 
 import javax.annotation.Nullable;
 
@@ -34,6 +35,7 @@ import org.apache.isis.applib.annotation.PromptStyle;
 import org.apache.isis.applib.layout.grid.Grid;
 import org.apache.isis.applib.layout.grid.bootstrap3.BS3Grid;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.collections._Lists;
 import org.apache.isis.metamodel.facets.object.grid.GridFacet;
@@ -104,19 +106,16 @@ public abstract class ActionLinkFactoryAbstract implements ActionLinkFactory {
 
                 if(toggledMementosProviderIfAny != null) {
 
-                    final List<ObjectAdapterMemento> selectedMementos =
+                    final Can<ObjectAdapterMemento> selectedMementos =
                             toggledMementosProviderIfAny.getToggles();
 
-                    final List<Object> selectedPojos = _Lists.transform(selectedMementos, stream->stream
-                            .map((@Nullable final ObjectAdapterMemento memento) -> {
-                                if(memento == null) {
-                                    return null;
-                                }
-                                val objectAdapter = memento.getObjectAdapter(commonContext.getSpecificationLoader());
-                                return objectAdapter != null ? objectAdapter.getPojo() : null;
-                            })
-                            .filter(_NullSafe::isPresent)
-                            );
+                    final List<Object> selectedPojos = selectedMementos.stream()
+                    .filter(_NullSafe::isPresent)
+                    .map(memento -> memento.getObjectAdapter(commonContext.getSpecificationLoader()))
+                    .filter(_NullSafe::isPresent)
+                    .map(ManagedObject::getPojo)
+                    .filter(_NullSafe::isPresent)
+                    .collect(Collectors.toList());
 
                     final ActionPrompt actionPrompt = ActionParameterDefaultsFacetFromAssociatedCollection.withSelected(
                             selectedPojos,
diff --git a/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/login/IsisSignInPanel.java b/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/login/IsisSignInPanel.java
index 376214e..5c7a1a2 100644
--- a/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/login/IsisSignInPanel.java
+++ b/core/viewer-wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/pages/login/IsisSignInPanel.java
@@ -31,7 +31,7 @@ import org.apache.isis.applib.services.inject.ServiceInjector;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
 import org.apache.isis.applib.services.userreg.EmailNotificationService;
 import org.apache.isis.applib.services.userreg.UserRegistrationService;
-import org.apache.isis.commons.collections.Bin;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.runtime.system.session.IsisSessionFactory;
 import org.apache.isis.viewer.wicket.model.models.PageType;
 import org.apache.isis.viewer.wicket.ui.pages.PageClassRegistry;
@@ -52,8 +52,8 @@ public class IsisSignInPanel extends SignInPanel {
     @Inject transient ServiceInjector serviceInjector;
     @Inject transient ServiceRegistry serviceRegistry;
     @Inject transient private PageClassRegistry pageClassRegistry;
-    transient Bin<UserRegistrationService> anyUserRegistrationService;
-    transient Bin<EmailNotificationService> anyEmailNotificationService;
+    transient Can<UserRegistrationService> anyUserRegistrationService;
+    transient Can<EmailNotificationService> anyEmailNotificationService;
 
     private final boolean signUpLink;
     private final boolean passwordResetLink;
diff --git a/extensions/fixtures/src/main/java/org/apache/isis/extensions/fixtures/fixturespec/FixtureScriptsDefault.java b/extensions/fixtures/src/main/java/org/apache/isis/extensions/fixtures/fixturespec/FixtureScriptsDefault.java
index 9884943..7d38c1d 100644
--- a/extensions/fixtures/src/main/java/org/apache/isis/extensions/fixtures/fixturespec/FixtureScriptsDefault.java
+++ b/extensions/fixtures/src/main/java/org/apache/isis/extensions/fixtures/fixturespec/FixtureScriptsDefault.java
@@ -36,7 +36,7 @@ import org.apache.isis.applib.annotation.ParameterLayout;
 import org.apache.isis.applib.annotation.RestrictTo;
 import org.apache.isis.applib.services.eventbus.EventBusService;
 import org.apache.isis.applib.services.registry.ServiceRegistry;
-import org.apache.isis.commons.collections.Bin;
+import org.apache.isis.commons.collections.Can;
 import org.apache.isis.extensions.fixtures.events.FixturesInstalledEvent;
 import org.apache.isis.extensions.fixtures.events.FixturesInstallingEvent;
 import org.apache.isis.extensions.fixtures.fixturescripts.FixtureResult;
@@ -240,7 +240,7 @@ public class FixtureScriptsDefault extends FixtureScripts {
         return fixtureScriptsSpecificationProvider.isEmpty() || getSpecification().getRunScriptDropDownPolicy() != requiredPolicy;
     }
 
-    private Bin<FixtureScriptsSpecificationProvider> fixtureScriptsSpecificationProvider;
+    private Can<FixtureScriptsSpecificationProvider> fixtureScriptsSpecificationProvider;
 
     // -- DEPS