You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2021/04/23 06:13:46 UTC

[isis] branch ISIS-2619 created (now 2a01980)

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

danhaywood pushed a change to branch ISIS-2619
in repository https://gitbox.apache.org/repos/asf/isis.git.


      at 2a01980  ISIS-2619: adds javadoc for FacetFactory

This branch includes the following new commits:

     new 3026c34  ISIS-2619: introduces new DeriveMixinMembersPostProcessor
     new 2a01980  ISIS-2619: adds javadoc for FacetFactory

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


[isis] 02/02: ISIS-2619: adds javadoc for FacetFactory

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch ISIS-2619
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 2a01980ee126cbb2bd14b7798991120093325deb
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Fri Apr 23 07:13:24 2021 +0100

    ISIS-2619: adds javadoc for FacetFactory
---
 .../isis/core/metamodel/facets/FacetFactory.java   | 111 ++++++++++++---------
 1 file changed, 66 insertions(+), 45 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/FacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/FacetFactory.java
index 9eaa73b..e142037 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/FacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/FacetFactory.java
@@ -33,11 +33,32 @@ import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
 import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MethodRemover;
+import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
 
 import lombok.Getter;
 import lombok.NonNull;
 import lombok.val;
 
+/**
+ * Responsible for processing elements of the metamodel, registered to the
+ * {@link org.apache.isis.core.metamodel.progmodel.ProgrammingModel} using
+ * {@link org.apache.isis.core.metamodel.progmodel.ProgrammingModel#addFactory(ProgrammingModel.FacetProcessingOrder, FacetFactory, ProgrammingModel.Marker...)}.
+ *
+ * <p>
+ *     IMPORTANT: with respect to mixed-in members, {@link FacetFactory}s are
+ *     only run against those members in their original form as an action of
+ *     a mixin class, <i>not</i> as contributed mixin methods of the mixee type.
+ *     This is because they actually run against {@link FacetedMethod}s, which
+ *     are the peer object that is wrapped by (the respective subclasses of)
+ *     {@link org.apache.isis.core.metamodel.spec.feature.ObjectMember}.
+ * </p>
+ *
+ * <p>
+ *     To process a mixin member in the context of it actually being a mixin
+ *     member (for example, authorization or translations), instead use the
+ *     {@link org.apache.isis.core.metamodel.specloader.postprocessor.PostProcessor} interface.
+ * </p>
+ */
 public interface FacetFactory {
 
     static class AbstractProcessContext<T extends FacetHolder> {
@@ -68,29 +89,29 @@ public interface FacetFactory {
         public Class<?> getCls() {
             return cls;
         }
-        
-        /** 
+
+        /**
          * Annotation lookup on this context's type (cls).
          * @since 2.0
          */
         public <A extends Annotation> Optional<A> synthesizeOnType(Class<A> annotationType) {
             return _Annotations.synthesizeInherited(cls, annotationType);
         }
-        
+
     }
 
-    static class AbstractProcessWithMethodContext<T extends FacetHolder> 
+    static class AbstractProcessWithMethodContext<T extends FacetHolder>
     extends AbstractProcessWithClsContext<T> implements MethodRemover{
 
         private final Method method;
         protected final MethodRemover methodRemover;
 
         AbstractProcessWithMethodContext(
-                final Class<?> cls, 
-                final Method method, 
-                final MethodRemover methodRemover, 
+                final Class<?> cls,
+                final Method method,
+                final MethodRemover methodRemover,
                 final T facetHolder) {
-            
+
             super(cls, facetHolder);
             this.method = method;
             this.methodRemover = methodRemover;
@@ -136,7 +157,7 @@ public interface FacetFactory {
      * Used by the Java5 Reflector's <tt>ProgrammingModel</tt> to reduce the
      * number of {@link FacetFactory factory}s that are queried when building up
      * the meta-model.
-     * 
+     *
      */
     ImmutableEnumSet<FeatureType> getFeatureTypes();
 
@@ -145,10 +166,10 @@ public interface FacetFactory {
     // process class
     // //////////////////////////////////////
 
-    public static class ProcessClassContext 
-    extends AbstractProcessWithClsContext<FacetHolder> 
+    public static class ProcessClassContext
+    extends AbstractProcessWithClsContext<FacetHolder>
     implements MethodRemover, ProcessContextWithMetadataProperties<FacetHolder> {
-        
+
         private final MethodRemover methodRemover;
 
         /**
@@ -182,27 +203,27 @@ public interface FacetFactory {
     // //////////////////////////////////////
 
 
-    public static class ProcessMethodContext 
-    extends AbstractProcessWithMethodContext<FacetedMethod> 
+    public static class ProcessMethodContext
+    extends AbstractProcessWithMethodContext<FacetedMethod>
     implements ProcessContextWithMetadataProperties<FacetedMethod> {
-        
+
         @Getter private final FeatureType featureType;
         /**
-         * Whether we are currently processing a mixin type AND this context's method can be identified 
-         * as the main method of the processed mixin class. 
+         * Whether we are currently processing a mixin type AND this context's method can be identified
+         * as the main method of the processed mixin class.
          * @since 2.0
          */
         @Getter private final boolean mixinMain;
 
         /**
-         * 
+         *
          * @param cls
          * @param featureType
          * @param method
          * @param methodRemover
          * @param facetedMethod
          * @param isMixinMain
-         *       - Whether we are currently processing a mixin type AND this context's method can be identified 
+         *       - Whether we are currently processing a mixin type AND this context's method can be identified
          *         as the main method of the processed mixin class. (since 2.0)
          */
         public ProcessMethodContext(
@@ -212,12 +233,12 @@ public interface FacetFactory {
                 final MethodRemover methodRemover,
                 final FacetedMethod facetedMethod,
                 final boolean isMixinMain) {
-            
+
             super(cls, method, methodRemover, facetedMethod);
             this.featureType = featureType;
             this.mixinMain = isMixinMain;
         }
-        
+
         /** JUnit support, historically not using 'isMixinMain' */
         public ProcessMethodContext(
                 final Class<?> cls,
@@ -228,45 +249,45 @@ public interface FacetFactory {
             this(cls, featureType, method, methodRemover, facetedMethod, false);
         }
 
-        
-        /** 
+
+        /**
          * Annotation lookup on this context's method. Also honors annotations on fields, if this method is a getter.
          * @since 2.0
          */
         public <A extends Annotation> Optional<A> synthesizeOnMethod(Class<A> annotationType) {
             return _Annotations.synthesizeInherited(getMethod(), annotationType);
         }
-        
-        /** 
-         * Annotation lookup on this context's method, if not found, extends search to type in case 
+
+        /**
+         * Annotation lookup on this context's method, if not found, extends search to type in case
          * the predicate {@link #isMixinMain} evaluates {@code true}.
          * <p>
-         * As of [ISIS-2604] we also make sure the annotation type does not appear in both places 
-         * (method and type). Hence the 2nd parameter is a callback that fires if the annotation 
-         * is found in both places. 
-         * 
+         * As of [ISIS-2604] we also make sure the annotation type does not appear in both places
+         * (method and type). Hence the 2nd parameter is a callback that fires if the annotation
+         * is found in both places.
+         *
          * @since 2.0
          */
         public <A extends Annotation> Optional<A> synthesizeOnMethodOrMixinType(
                 final @NonNull Class<A> annotationType,
                 final @NonNull Runnable onAmbiguity) {
-            
-            
+
+
             val onMethod = synthesizeOnMethod(annotationType);
             val onType = synthesizeOnType(annotationType);
-            
+
             if(onMethod.isPresent()) {
                 if(onType.isPresent()) {
-                    onAmbiguity.run();    
+                    onAmbiguity.run();
                 }
                 return onMethod;
             }
             return onType;
         }
-        
+
     }
-    
-    
+
+
     /**
      * Process the method, and return the correctly setup annotation if present.
      */
@@ -274,12 +295,12 @@ public interface FacetFactory {
 
     // -- PROCESS PARAM
 
-    public static class ProcessParameterContext 
+    public static class ProcessParameterContext
     extends AbstractProcessWithMethodContext<FacetedMethodParameter> {
-        
+
         private final int paramNum;
         private final Class<?> paramType;
-        private final Parameter parameter; 
+        private final Parameter parameter;
 
         public ProcessParameterContext(
                 final Class<?> cls,
@@ -287,7 +308,7 @@ public interface FacetFactory {
                 final int paramNum,
                 final MethodRemover methodRemover,
                 final FacetedMethodParameter facetedMethodParameter) {
-            
+
             super(cls, method, methodRemover, facetedMethodParameter);
             if(paramNum>=method.getParameterCount()) {
                 throw _Exceptions.unrecoverable("invalid ProcessParameterContext");
@@ -300,8 +321,8 @@ public interface FacetFactory {
         public int getParamNum() {
             return paramNum;
         }
-        
-        /** 
+
+        /**
          * Annotation lookup on this context's method parameter.
          * @since 2.0
          */
@@ -315,7 +336,7 @@ public interface FacetFactory {
         public Class<?> getParameterType() {
             return this.paramType;
         }
-        
+
         /**
          * @since 2.0
          */
@@ -330,5 +351,5 @@ public interface FacetFactory {
      */
     void processParams(ProcessParameterContext processParameterContext);
 
-    
+
 }

[isis] 01/02: ISIS-2619: introduces new DeriveMixinMembersPostProcessor

Posted by da...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

danhaywood pushed a commit to branch ISIS-2619
in repository https://gitbox.apache.org/repos/asf/isis.git

commit 3026c349409c3663c7db7bb5edd4f8ebcc1953e2
Author: danhaywood <da...@haywood-associates.co.uk>
AuthorDate: Fri Apr 23 07:04:24 2021 +0100

    ISIS-2619: introduces new DeriveMixinMembersPostProcessor
---
 .../param/DeriveMixinMembersPostProcessor.java     | 65 ++++++++++++++++++
 .../dflt/ProgrammingModelFacetsJava8.java          | 13 ++--
 .../specloader/facetprocessor/FacetProcessor.java  | 78 +++++++++++-----------
 .../facets/TenantedAuthorizationFacetFactory.java  | 14 ++--
 4 files changed, 121 insertions(+), 49 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/param/DeriveMixinMembersPostProcessor.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/param/DeriveMixinMembersPostProcessor.java
new file mode 100644
index 0000000..8207049
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/postprocessors/param/DeriveMixinMembersPostProcessor.java
@@ -0,0 +1,65 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+
+package org.apache.isis.core.metamodel.postprocessors.param;
+
+import java.util.stream.Stream;
+
+import org.apache.isis.core.metamodel.context.MetaModelContext;
+import org.apache.isis.core.metamodel.context.MetaModelContextAware;
+import org.apache.isis.core.metamodel.facets.FacetedMethod;
+import org.apache.isis.core.metamodel.progmodel.ObjectSpecificationPostProcessor;
+import org.apache.isis.core.metamodel.spec.ActionType;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.MixedIn;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.metamodel.spec.feature.ObjectMember;
+import org.apache.isis.core.metamodel.spec.feature.OneToManyAssociation;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+import org.apache.isis.core.metamodel.specloader.specimpl.ObjectMemberAbstract;
+
+import lombok.Setter;
+import lombok.val;
+
+
+public class DeriveMixinMembersPostProcessor
+implements ObjectSpecificationPostProcessor, MetaModelContextAware {
+
+    @Setter(onMethod = @__(@Override))
+    private MetaModelContext metaModelContext;
+
+    @Override
+    public void postProcess(final ObjectSpecification objectSpecification) {
+
+        // all the actions of this type
+        val actionTypes = metaModelContext.getSystemEnvironment().isPrototyping()
+                ? ActionType.USER_AND_PROTOTYPE
+                : ActionType.USER_ONLY;
+        objectSpecification.streamActions(actionTypes, MixedIn.INCLUDED);
+
+        // and all the collections of this type
+        objectSpecification.streamCollections(MixedIn.INCLUDED);
+
+        // and all the properties of this type
+        objectSpecification.streamProperties(MixedIn.INCLUDED);
+
+    }
+
+
+}
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/progmodels/dflt/ProgrammingModelFacetsJava8.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/progmodels/dflt/ProgrammingModelFacetsJava8.java
index 8f55ad8..23ce56c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/progmodels/dflt/ProgrammingModelFacetsJava8.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/progmodels/dflt/ProgrammingModelFacetsJava8.java
@@ -143,6 +143,7 @@ import org.apache.isis.core.metamodel.methods.MemberSupportAnnotationEnforcesSup
 import org.apache.isis.core.metamodel.methods.MethodByClassMap;
 import org.apache.isis.core.metamodel.methods.OrphanedSupportingMethodValidator;
 import org.apache.isis.core.metamodel.postprocessors.param.DeriveFacetsPostProcessor;
+import org.apache.isis.core.metamodel.postprocessors.param.DeriveMixinMembersPostProcessor;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModelAbstract;
 import org.apache.isis.core.metamodel.services.title.TitlesAndTranslationsValidator;
 
@@ -236,7 +237,7 @@ public final class ProgrammingModelFacetsJava8 extends ProgrammingModelAbstract
         addFactory(FacetProcessingOrder.E1_MEMBER_MODELLING, DisabledObjectFacetViaMethodFactory.class);
 
         val postConstructMethodsCache = new MethodByClassMap();
-        
+
         addFactory(FacetProcessingOrder.E1_MEMBER_MODELLING, new RecreatableObjectFacetFactory(postConstructMethodsCache));
         addFactory(FacetProcessingOrder.E1_MEMBER_MODELLING, JaxbFacetFactory.class);
 
@@ -256,7 +257,7 @@ public final class ProgrammingModelFacetsJava8 extends ProgrammingModelAbstract
         // must come after DomainObjectAnnotationFacetFactory & MixinFacetFactory
         addFactory(FacetProcessingOrder.E1_MEMBER_MODELLING, ContributingFacetDerivedFromMixinFacetFactory.class);
 
-        
+
         addFactory(FacetProcessingOrder.F1_LAYOUT, GridFacetFactory.class);
 
         // must come before DomainObjectLayoutFacetFactory
@@ -327,7 +328,7 @@ public final class ProgrammingModelFacetsJava8 extends ProgrammingModelAbstract
         addFactory(FacetProcessingOrder.G1_VALUE_TYPES, OffsetDateTimeValueFacetUsingSemanticsProviderFactory.class);
         addFactory(FacetProcessingOrder.G1_VALUE_TYPES, ZonedDateTimeValueFacetUsingSemanticsProviderFactory.class);
 
-        addFactory(FacetProcessingOrder.Z0_BEFORE_FINALLY, AuthorizationFacetFactory.class);
+        addFactory(FacetProcessingOrder.Z0_BEFORE_FINALLY, AuthorizationFacetFactory.class); // TODO: reimplement as a PostProcessor
 
         // written to not trample over TypeOf if already installed
         addFactory(FacetProcessingOrder.Z1_FINALLY, CollectionFacetFactory.class);
@@ -346,12 +347,14 @@ public final class ProgrammingModelFacetsJava8 extends ProgrammingModelAbstract
         addFactory(FacetProcessingOrder.Z1_FINALLY, FacetsFacetAnnotationFactory.class);
 
         // must be after all named facets and description facets have been installed
-        addFactory(FacetProcessingOrder.Z1_FINALLY, TranslationFacetFactory.class);
+        addFactory(FacetProcessingOrder.Z1_FINALLY, TranslationFacetFactory.class); // TODO: reimplement as a PostProcessor
+
 
         addFactory(FacetProcessingOrder.Z1_FINALLY, ViewModelSemanticCheckingFacetFactory.class);
 
+        addPostProcessor(PostProcessingOrder.A0_BEFORE_BUILTIN, DeriveMixinMembersPostProcessor.class);
         addPostProcessor(PostProcessingOrder.A1_BUILTIN, DeriveFacetsPostProcessor.class);
-        
+
         addValidator(new MemberSupportAnnotationEnforcesSupportingMethodValidator());
         addValidator(new OrphanedSupportingMethodValidator());
         addValidator(new TitlesAndTranslationsValidator());
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/facetprocessor/FacetProcessor.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/facetprocessor/FacetProcessor.java
index ab133f7..a038a92 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/facetprocessor/FacetProcessor.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/facetprocessor/FacetProcessor.java
@@ -80,7 +80,7 @@ public class FacetProcessor {
      * {@link MethodPrefixBasedFacetFactory}.
      *
      */
-    private final _Lazy<Set<String>> methodPrefixes = 
+    private final _Lazy<Set<String>> methodPrefixes =
             _Lazy.threadSafe(this::init_methodPrefixes);
 
     /**
@@ -111,13 +111,13 @@ public class FacetProcessor {
      * Lazily initialized, then cached. The lists remain in the same order that
      * the factories were {@link #registerFactory(FacetFactory) registered}.
      */
-    private final _Lazy<ListMultimap<FeatureType, FacetFactory>> factoryListByFeatureType = 
+    private final _Lazy<ListMultimap<FeatureType, FacetFactory>> factoryListByFeatureType =
             _Lazy.threadSafe(this::init_factoriesByFeatureType);
-    
+
     // -- LIFECYCLE
-    
+
     public void init() {
-        cleanUp(); 
+        cleanUp();
         programmingModel.streamFactories()
         .forEach(this::registerFactory);
     }
@@ -131,7 +131,7 @@ public class FacetProcessor {
         factories.clear();
         factoryByFactoryType.clear();
     }
-    
+
     private void registerFactory(FacetFactory factory) {
         factoryByFactoryType.put(factory.getClass(), factory);
         factories.add(factory);
@@ -155,11 +155,11 @@ public class FacetProcessor {
      * {@link PropertyOrCollectionIdentifyingFacetFactory}s.
      */
     public void findAssociationCandidateAccessors(
-            Stream<Method> methods, 
+            Stream<Method> methods,
             Consumer<Method> onCandidate) {
-        
+
         val factories = propertyOrCollectionIdentifyingFactories.get();
-        
+
         methods.forEach(method->{
             for (val facetFactory : factories) {
                 if (facetFactory.isPropertyOrCollectionAccessorCandidate(method)) {
@@ -178,9 +178,9 @@ public class FacetProcessor {
      * Intended to be called after {@link #findAndRemovePropertyAccessors(MethodRemover, java.util.List)} once only reference properties remain.
      */
     public void findAndRemovePropertyAccessors(
-            MethodRemover methodRemover, 
+            MethodRemover methodRemover,
             List<Method> methodListToAppendTo) {
-        
+
         for (val facetFactory : propertyOrCollectionIdentifyingFactories.get()) {
             facetFactory.findAndRemovePropertyAccessors(methodRemover, methodListToAppendTo);
         }
@@ -195,9 +195,9 @@ public class FacetProcessor {
      *      List)
      */
     public void findAndRemoveCollectionAccessors(
-            MethodRemover methodRemover, 
+            MethodRemover methodRemover,
             List<Method> methodListToAppendTo) {
-        
+
         for (val facetFactory : propertyOrCollectionIdentifyingFactories.get()) {
             facetFactory.findAndRemoveCollectionAccessors(methodRemover, methodListToAppendTo);
         }
@@ -247,11 +247,11 @@ public class FacetProcessor {
 
     private List<ObjectSpecIdFacetFactory> objectSpecIfFacetFactoryList = null;
 
-    
+
     private List<ObjectSpecIdFacetFactory> getObjectSpecIfFacetFactoryList() {
         if(objectSpecIfFacetFactoryList == null) {
             val facetFactories = _Lists.<ObjectSpecIdFacetFactory>newArrayList();
-            
+
             factoryListByFeatureType.get().getOrElseEmpty(FeatureType.OBJECT)
             .forEach(facetFactory->{
                 if (facetFactory instanceof ObjectSpecIdFacetFactory) {
@@ -259,7 +259,7 @@ public class FacetProcessor {
                     facetFactories.add(objectSpecIdFacetFactory);
                 }
             });
-            
+
             objectSpecIfFacetFactoryList = Collections.unmodifiableList(facetFactories);
         }
         return objectSpecIfFacetFactoryList;
@@ -284,12 +284,12 @@ public class FacetProcessor {
             Class<?> cls,
             MethodRemover methodRemover,
             FacetHolder facetHolder) {
-        
+
         val ctx = new ProcessClassContext(
-                cls, 
-                removerElseNoopRemover(methodRemover), 
+                cls,
+                removerElseNoopRemover(methodRemover),
                 facetHolder);
-        
+
         factoryListByFeatureType.get().getOrElseEmpty(FeatureType.OBJECT)
         .forEach(facetFactory->facetFactory.process(ctx));
     }
@@ -315,7 +315,7 @@ public class FacetProcessor {
      *            - what type of feature the method represents (property,
      *            action, collection etc)
      * @param isMixinMain
-     *            - Whether we are currently processing a mixin type AND this context's method 
+     *            - Whether we are currently processing a mixin type AND this context's method
      *            can be identified as the main method of the processed mixin class. (since 2.0)
      */
     public void process(
@@ -323,24 +323,26 @@ public class FacetProcessor {
             Method method,
             MethodRemover methodRemover,
             FacetedMethod facetedMethod,
-            FeatureType featureType, 
+            FeatureType featureType,
             boolean isMixinMain) {
-        
+
         facetedMethod.setMetaModelContext(metaModelContext);
-        
+
         val processMethodContext =
                 new ProcessMethodContext(
-                        cls, 
-                        featureType, 
-                        method, 
+                        cls,
+                        featureType,
+                        method,
                         removerElseNoopRemover(methodRemover), facetedMethod, isMixinMain);
-        
-        factoryListByFeatureType.get().getOrElseEmpty(featureType)
-        .forEach(facetFactory->facetFactory.process(processMethodContext));
+
+        for (FacetFactory facetFactory : factoryListByFeatureType.get().getOrElseEmpty(featureType)) {
+
+            facetFactory.process(processMethodContext);
+        }
     }
 
     public void processMemberOrder(ObjectMember facetHolder) {
-        
+
     }
 
     /**
@@ -367,9 +369,9 @@ public class FacetProcessor {
             int paramNum,
             MethodRemover methodRemover,
             FacetedMethodParameter facetedMethodParameter) {
-        
+
         facetedMethodParameter.setMetaModelContext(metaModelContext);
-        
+
         for (val featureType : FeatureType.PARAMETERS_ONLY) {
             processParams(introspectedClass, method, paramNum, methodRemover, facetedMethodParameter, featureType);
         }
@@ -382,12 +384,12 @@ public class FacetProcessor {
             MethodRemover methodRemover,
             FacetedMethodParameter facetedMethodParameter,
             FeatureType featureType) {
-        
+
         facetedMethodParameter.setMetaModelContext(metaModelContext);
-        
+
         val processParameterContext =
                 new ProcessParameterContext(introspectedClass, method, paramNum, methodRemover, facetedMethodParameter);
-        
+
         factoryListByFeatureType.get().getOrElseEmpty(featureType)
         .forEach(facetFactory->facetFactory.processParams(processParameterContext));
     }
@@ -399,7 +401,7 @@ public class FacetProcessor {
         methodFilteringFactories.clear();
         propertyOrCollectionIdentifyingFactories.clear();
     }
-    
+
     // -- INITIALIZERS
 
     private ListMultimap<FeatureType, FacetFactory> init_factoriesByFeatureType() {
@@ -443,7 +445,7 @@ public class FacetProcessor {
         }
         return propertyOrCollectionIdentifyingFactories;
     }
-    
+
     // -- HELPER
 
     private static MethodRemover removerElseNoopRemover(MethodRemover methodRemover) {
diff --git a/extensions/security/secman/model/src/main/java/org/apache/isis/extensions/secman/model/facets/TenantedAuthorizationFacetFactory.java b/extensions/security/secman/model/src/main/java/org/apache/isis/extensions/secman/model/facets/TenantedAuthorizationFacetFactory.java
index a60e300..d08b5ba 100644
--- a/extensions/security/secman/model/src/main/java/org/apache/isis/extensions/secman/model/facets/TenantedAuthorizationFacetFactory.java
+++ b/extensions/security/secman/model/src/main/java/org/apache/isis/extensions/secman/model/facets/TenantedAuthorizationFacetFactory.java
@@ -33,6 +33,7 @@ import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facetapi.MetaModelRefiner;
 import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract;
 import org.apache.isis.core.metamodel.progmodel.ProgrammingModel;
+import org.apache.isis.core.metamodel.specloader.SpecificationLoader;
 import org.apache.isis.extensions.secman.api.tenancy.ApplicationTenancyEvaluator;
 import org.apache.isis.extensions.secman.api.user.ApplicationUserRepository;
 
@@ -78,35 +79,36 @@ public class TenantedAuthorizationFacetFactory extends FacetFactoryAbstract {
         FacetUtil.addFacet(createFacet(cls, facetHolder));
     }
 
-    
+
     public static class QueryResultsCacheProviderHolder {
         @Inject @Getter private Provider<QueryResultsCache> queryResultsCacheProvider;
     }
-    
+
     @SuppressWarnings({ "rawtypes", "unchecked" })
     private TenantedAuthorizationFacetDefault createFacet(
-            final Class<?> cls, 
+            final Class<?> cls,
             final FacetHolder holder) {
 
         val serviceRegistry = super.getServiceRegistry();
 
+        final boolean mixinClass = serviceRegistry.lookupService(SpecificationLoader.class).map(x -> x.loadSpecification(cls)).map(x -> x.isMixin()).isPresent();
         val evaluators = serviceRegistry
                 .select(ApplicationTenancyEvaluator.class)
                 .stream()
-                .filter(applicationTenancyEvaluator->applicationTenancyEvaluator.handles(cls))
+                .filter(applicationTenancyEvaluator-> mixinClass || applicationTenancyEvaluator.handles(cls))
                 .collect(Collectors.<ApplicationTenancyEvaluator>toList());
 
         if(evaluators.isEmpty()) {
             return null;
         }
-        
+
         val applicationUserRepository =
                 serviceRegistry.lookupService(ApplicationUserRepository.class).orElse(null);
         val queryResultsCacheProvider =
                 super.getServiceInjector()
                 .injectServicesInto(new QueryResultsCacheProviderHolder())
                 .getQueryResultsCacheProvider();
-        val userService = 
+        val userService =
                 serviceRegistry.lookupService(UserService.class).orElse(null);
 
         return new TenantedAuthorizationFacetDefault(