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/12/15 22:31:57 UTC

[isis] branch master updated: ISIS-2226: introduces DependentArgUtils for consolidation

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 91276ff  ISIS-2226: introduces DependentArgUtils for consolidation
91276ff is described below

commit 91276ff116c9c5b3fbdc32bf1303f58ef36a2dbd
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sun Dec 15 23:31:44 2019 +0100

    ISIS-2226: introduces DependentArgUtils for consolidation
    
    it appears dependent args have not yet been implemented for
    autoComplete, hide and disable
    
    moves logic from ActionParameterAutoCompleteFacetViaMethodFactory to
    DependentArgUtils in order to allow reusing with
    ActionParameterAutoCompleteFacetViaMethodFactory
    
    fixes autoComplete with dependent args not picked up by the MM
---
 .../isis/metamodel/facets/DependentArgUtils.java   | 138 +++++++++++++++++++++
 .../metamodel/facets/FacetFactoryAbstract.java     |   1 -
 .../isis/metamodel/facets/MethodFinderUtils.java   |  39 ++++--
 .../MethodPrefixBasedFacetFactoryAbstract.java     |  14 ++-
 .../ActionParameterAutoCompleteFacetAbstract.java  |   4 +-
 ...ParameterAutoCompleteFacetViaMethodFactory.java | 116 +++++++++++------
 .../ActionParameterChoicesFacetViaMethod.java      |   3 +-
 ...ctionParameterChoicesFacetViaMethodFactory.java | 102 +++++----------
 .../actions/ActionMethodsFacetFactoryTest.java     |   7 +-
 ...nnotationFacetFactoryTest_ActionInvocation.java |  14 +--
 .../DependentArgsActionDemo_useAutoComplete.java   |   2 +-
 .../DependentArgsActionDemo_useChoices.java        |   2 +-
 .../DependentArgsActionDemo_useDefault.java        |   2 +-
 .../DependentArgsActionDemo_useDisable.java        |   2 +-
 .../depargs/DependentArgsActionDemo_useHide.java   |   2 +-
 .../testdomain/model/good/ProperMemberSupport.java |  10 +-
 .../model/good/ProperMemberSupport_action2.java    |  16 ++-
 17 files changed, 330 insertions(+), 144 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/DependentArgUtils.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/DependentArgUtils.java
new file mode 100644
index 0000000..7ff5361
--- /dev/null
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/DependentArgUtils.java
@@ -0,0 +1,138 @@
+/*
+ *  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.metamodel.facets;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.function.Consumer;
+import java.util.function.IntFunction;
+
+import javax.annotation.Nullable;
+
+import org.apache.isis.commons.internal.collections._Arrays;
+import org.apache.isis.metamodel.facets.FacetFactory.ProcessMethodContext;
+
+import lombok.Getter;
+import lombok.Value;
+import lombok.val;
+import lombok.experimental.UtilityClass;
+
+/**
+ * 
+ * @since 2.0
+ *
+ */
+@UtilityClass
+public class DependentArgUtils {
+    
+    @Value(staticConstructor = "of")
+    public static class ParamSupportingMethodSearchRequest {
+        ProcessMethodContext processMethodContext;
+        Class<?> additionalParamType;
+        IntFunction<String> paramIndexToMethodName;
+        
+        @Getter(lazy = true)
+        Class<?>[] paramTypes = getProcessMethodContext().getMethod().getParameterTypes();
+    }
+    
+    @Value(staticConstructor = "of")
+    public static class ParamSupportingMethodSearchResult {
+        int paramIndex;
+        Class<?> paramType;
+        Method supportingMethod;
+        Class<?> returnType;
+    }
+
+    public void findParamSupportingMethods(
+            final DependentArgUtils.ParamSupportingMethodSearchRequest searchRequest, 
+            final Consumer<DependentArgUtils.ParamSupportingMethodSearchResult> onMethodFound) {
+        
+        val actionMethod = searchRequest.getProcessMethodContext().getMethod();
+        val paramCount = actionMethod.getParameterCount();
+        
+        for (int i = 0; i < paramCount; i++) {
+
+            val paramIndex = i;
+            val searchResult = findParamSupportingMethod(searchRequest, paramIndex);
+
+            if (searchResult != null) {
+                onMethodFound.accept(searchResult);
+            }
+        }
+        
+    }
+
+    /*
+     * search successively for the supporting method, trimming number of param types each loop
+     */
+    private static DependentArgUtils.ParamSupportingMethodSearchResult findParamSupportingMethod(
+            final DependentArgUtils.ParamSupportingMethodSearchRequest searchRequest,
+            final int paramIndex) {
+
+        val processMethodContext = searchRequest.getProcessMethodContext();
+        val type = processMethodContext.getCls();
+        val paramTypes = searchRequest.getParamTypes();
+        val methodName = searchRequest.getParamIndexToMethodName().apply(paramIndex);
+        val paramType = paramTypes[paramIndex];
+        val additionalParamType = searchRequest.getAdditionalParamType();
+        
+        int paramsConsidered = paramTypes.length - 1; 
+        while(paramsConsidered>=0) {
+        
+            val paramTypesToLookFor = concat(paramTypes, paramsConsidered, additionalParamType);
+            
+            val supportingMethod = MethodFinderUtils
+                    .findMethod_returningNonScalar(type, methodName, paramType, paramTypesToLookFor);
+            
+            if(supportingMethod != null) {
+                val searchResult = ParamSupportingMethodSearchResult.of(
+                        paramIndex, paramType, supportingMethod, supportingMethod.getReturnType());
+                return searchResult;
+            }
+
+            // remove last, and search again
+            paramsConsidered--;
+        }
+
+        return null;
+    }
+    
+    public static Class<?>[] concat(
+            final Class<?>[] paramTypes,
+            final int paramsConsidered,
+            @Nullable final Class<?> additionalParamType) {
+
+        if(paramsConsidered>paramTypes.length) {
+            val msg = String.format("paramsConsidered %d exceeds size of paramTypes %d", 
+                    paramsConsidered, paramTypes.length);
+            throw new IllegalArgumentException(msg);
+        }
+        
+        val paramTypesConsidered = paramsConsidered<paramTypes.length
+                ? Arrays.copyOf(paramTypes, paramsConsidered)
+                        : paramTypes;
+                
+        val withAdditional = additionalParamType!=null
+                ? _Arrays.combine(paramTypesConsidered, additionalParamType)
+                        : paramTypesConsidered;
+                
+        return withAdditional;
+    }
+    
+}
\ No newline at end of file
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/FacetFactoryAbstract.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/FacetFactoryAbstract.java
index ddb88c6..12cd01e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/FacetFactoryAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/FacetFactoryAbstract.java
@@ -67,5 +67,4 @@ implements FacetFactory, MetaModelContextAware, MetaModelContext.Delegating {
     protected static final Class<?>[] NO_ARG = new Class<?>[0];
     protected static final Class<?>[] STRING_ARG = new Class<?>[] {String.class};
 
-
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/MethodFinderUtils.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/MethodFinderUtils.java
index 3179f85..e0b4563 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/MethodFinderUtils.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/MethodFinderUtils.java
@@ -19,8 +19,13 @@
 package org.apache.isis.metamodel.facets;
 
 import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
 import java.lang.reflect.Method;
-import java.util.*;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
 import java.util.stream.Collectors;
 
 import org.apache.isis.applib.services.i18n.TranslatableString;
@@ -50,9 +55,9 @@ public final class MethodFinderUtils {
     public static Method findMethod(
             final Class<?> type,
             final String name,
-            final Class<?> returnType,
+            final Class<?> expectedReturnType,
             final Class<?>[] paramTypes) {
-
+        
         val methodCache = _MethodCache.getInstance();
         
         val method = methodCache.lookupMethod(type, name, paramTypes);
@@ -72,12 +77,12 @@ public final class MethodFinderUtils {
             return null;
         }
 
-        if (returnType != null && !returnType.isAssignableFrom(method.getReturnType())) {
+        if (expectedReturnType != null && !expectedReturnType.isAssignableFrom(method.getReturnType())) {
             return null;
         }
 
         if (paramTypes != null) {
-            final Class<?>[] parameterTypes = method.getParameterTypes();
+            val parameterTypes = method.getParameterTypes();
             if (paramTypes.length != parameterTypes.length) {
                 return null;
             }
@@ -91,8 +96,7 @@ public final class MethodFinderUtils {
 
         return method;
     }
-
-
+    
     public static Method findMethod_returningAnyOf(
             final Class<?>[] returnTypes,
             final Class<?> type,
@@ -107,7 +111,7 @@ public final class MethodFinderUtils {
         }
         return null;
     }
-
+    
     public static Method findMethod(final Class<?> type, final String name, final Class<?> returnType) {
         try {
             final Method[] methods = type.getMethods();
@@ -125,7 +129,9 @@ public final class MethodFinderUtils {
         }
     }
 
-    public static List<Method> findMethodsWithAnnotation(final Class<?> type, final Class<? extends Annotation> annotationClass) {
+    public static List<Method> findMethodsWithAnnotation(
+            final Class<?> type, 
+            final Class<? extends Annotation> annotationClass) {
 
         // Validate arguments
         if (type == null || annotationClass == null) {
@@ -192,6 +198,8 @@ public final class MethodFinderUtils {
         return nullableMethod;
     }
 
+    
+    
     // -- SHORTCUTS
     
     public static final Class<?>[] TEXT_TYPES = new Class<?>[]{
@@ -205,5 +213,18 @@ public final class MethodFinderUtils {
             final Class<?>[] paramTypes) {
         return findMethod_returningAnyOf(TEXT_TYPES, type, name, paramTypes);
     }
+    
+    public static Method findMethod_returningNonScalar(
+            final Class<?> type,
+            final String name, 
+            final Class<?> elementReturnType,
+            final Class<?>[] paramTypes) {
+        
+        val nonScalarTypes = new Class<?>[]{
+            Collection.class, 
+            Array.newInstance(elementReturnType, 0).getClass()};
+        
+        return findMethod_returningAnyOf(nonScalarTypes, type, name, paramTypes);
+    }
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/MethodPrefixBasedFacetFactoryAbstract.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/MethodPrefixBasedFacetFactoryAbstract.java
index 319b82d..26a2bf9 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/MethodPrefixBasedFacetFactoryAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/MethodPrefixBasedFacetFactoryAbstract.java
@@ -36,7 +36,7 @@ implements MethodPrefixBasedFacetFactory {
     @Getter(onMethod = @__(@Override))
     private final Can<String> prefixes;
 
-    private final OrphanValidation orphanValidation; 
+    private final OrphanValidation orphanValidation;
 
     protected enum OrphanValidation {
         VALIDATE,
@@ -107,10 +107,6 @@ implements MethodPrefixBasedFacetFactory {
         });
     }
 
-    private static boolean isPrefixed(String actionId, String prefix) {
-        return actionId.startsWith(prefix) && actionId.length() > prefix.length();
-    }
-
     protected boolean isPropertyOrMixinMain(ProcessMethodContext processMethodContext) {
         return processMethodContext.isMixinMain() 
                 || (
@@ -118,5 +114,13 @@ implements MethodPrefixBasedFacetFactory {
                         && processMethodContext.getFeatureType().isProperty()
                    );
     }
+    
+    // -- HELPER
+    
+    private static boolean isPrefixed(String actionId, String prefix) {
+        return actionId.startsWith(prefix) && actionId.length() > prefix.length();
+    }
+
+
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/autocomplete/ActionParameterAutoCompleteFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/autocomplete/ActionParameterAutoCompleteFacetAbstract.java
index 9062ab5..f7d9833 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/autocomplete/ActionParameterAutoCompleteFacetAbstract.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/autocomplete/ActionParameterAutoCompleteFacetAbstract.java
@@ -23,7 +23,9 @@ import org.apache.isis.metamodel.facetapi.Facet;
 import org.apache.isis.metamodel.facetapi.FacetAbstract;
 import org.apache.isis.metamodel.facetapi.FacetHolder;
 
-public abstract class ActionParameterAutoCompleteFacetAbstract extends FacetAbstract implements ActionParameterAutoCompleteFacet {
+public abstract class ActionParameterAutoCompleteFacetAbstract 
+extends FacetAbstract 
+implements ActionParameterAutoCompleteFacet {
 
     public static Class<? extends Facet> type() {
         return ActionParameterAutoCompleteFacet.class;
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/autocomplete/method/ActionParameterAutoCompleteFacetViaMethodFactory.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/autocomplete/method/ActionParameterAutoCompleteFacetViaMethodFactory.java
index cbba636..df7742e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/autocomplete/method/ActionParameterAutoCompleteFacetViaMethodFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/autocomplete/method/ActionParameterAutoCompleteFacetViaMethodFactory.java
@@ -19,20 +19,20 @@
 
 package org.apache.isis.metamodel.facets.param.autocomplete.method;
 
-import java.lang.reflect.Array;
-import java.lang.reflect.Method;
-import java.util.Collection;
 import java.util.List;
-import java.util.Set;
 
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.metamodel.commons.StringExtensions;
+import org.apache.isis.metamodel.exceptions.MetaModelException;
 import org.apache.isis.metamodel.facetapi.FeatureType;
+import org.apache.isis.metamodel.facets.DependentArgUtils;
 import org.apache.isis.metamodel.facets.FacetedMethod;
 import org.apache.isis.metamodel.facets.FacetedMethodParameter;
-import org.apache.isis.metamodel.facets.MethodFinderUtils;
 import org.apache.isis.metamodel.facets.MethodLiteralConstants;
 import org.apache.isis.metamodel.facets.MethodPrefixBasedFacetFactoryAbstract;
+import org.apache.isis.metamodel.facets.param.autocomplete.ActionParameterAutoCompleteFacet;
+
+import lombok.val;
 
 public class ActionParameterAutoCompleteFacetViaMethodFactory extends MethodPrefixBasedFacetFactoryAbstract {
 
@@ -55,51 +55,93 @@ public class ActionParameterAutoCompleteFacetViaMethodFactory extends MethodPref
         attachAutoCompleteFacetForParametersIfAutoCompleteNumMethodIsFound(processMethodContext, holderList);
 
     }
-
-    private void attachAutoCompleteFacetForParametersIfAutoCompleteNumMethodIsFound(final ProcessMethodContext processMethodContext, final List<FacetedMethodParameter> parameters) {
+    
+    private void attachAutoCompleteFacetForParametersIfAutoCompleteNumMethodIsFound(
+            final ProcessMethodContext processMethodContext, 
+            final List<FacetedMethodParameter> parameters) {
 
         if (parameters.isEmpty()) {
             return;
         }
 
-        final Method actionMethod = processMethodContext.getMethod();
-        final Class<?>[] params = actionMethod.getParameterTypes();
+        val actionMethod = processMethodContext.getMethod();
+        val capitalizedName = StringExtensions.asCapitalizedName(actionMethod.getName());
 
-        for (int i = 0; i < params.length; i++) {
+        val searchRequest = DependentArgUtils.ParamSupportingMethodSearchRequest.of(
+                processMethodContext,
+                String.class,
+                paramIndex -> MethodLiteralConstants.AUTO_COMPLETE_PREFIX + paramIndex + capitalizedName);    
 
-            final Class<?> paramType = params[i];
-            final Class<?> arrayOfParamType = (Array.newInstance(paramType, 0)).getClass();
-
-            @SuppressWarnings("rawtypes")
-            final Class[] returnTypes = { arrayOfParamType, List.class, Set.class, Collection.class };
-            Method autoCompleteMethod = findAutoCompleteNumMethodReturning(processMethodContext, i, returnTypes);
-            if (autoCompleteMethod == null) {
-                continue;
-            }
+        DependentArgUtils.findParamSupportingMethods(searchRequest, searchResult -> {
+            
+            val autoCompleteMethod = searchResult.getSupportingMethod();
+            val paramIndex = searchResult.getParamIndex();
+            val paramType = searchResult.getParamType();
+            
             processMethodContext.removeMethod(autoCompleteMethod);
 
+            val facetedMethod = processMethodContext.getFacetHolder();
+            if (facetedMethod.containsNonFallbackFacet(ActionParameterAutoCompleteFacet.class)) {
+                val cls = processMethodContext.getCls();
+                throw new MetaModelException(cls + " uses both old and new autoComplete syntax - "
+                        + "must use one or other");
+            }
+            
             // add facets directly to parameters, not to actions
-            final FacetedMethodParameter paramAsHolder = parameters.get(i);
+            val paramAsHolder = parameters.get(paramIndex);
             super.addFacet(
                     new ActionParameterAutoCompleteFacetViaMethod(
                             autoCompleteMethod, paramType, paramAsHolder));
-        }
-    }
-
-    private Method findAutoCompleteNumMethodReturning(
-            final ProcessMethodContext processMethodContext,
-            final int paramNum,
-            final Class<?>[] returnTypes) {
-
-        final Class<?> cls = processMethodContext.getCls();
-        final Method actionMethod = processMethodContext.getMethod();
-        final String capitalizedName = StringExtensions.asCapitalizedName(actionMethod.getName());
-        final String name = MethodLiteralConstants.AUTO_COMPLETE_PREFIX + paramNum + capitalizedName;
-        return MethodFinderUtils.findMethod_returningAnyOf(
-                returnTypes,
-                cls,
-                name,
-                STRING_ARG);
+        });
+        
     }
+    
+// legacy of ...
+//    private void attachAutoCompleteFacetForParametersIfAutoCompleteNumMethodIsFound(
+//            final ProcessMethodContext processMethodContext, 
+//            final List<FacetedMethodParameter> parameters) {
+//
+//        if (parameters.isEmpty()) {
+//            return;
+//        }
+//
+//        val actionMethod = processMethodContext.getMethod();
+//        val paramTypes = actionMethod.getParameterTypes();
+//
+//        for (int i = 0; i < paramTypes.length; i++) {
+//
+//            final Class<?> paramType = paramTypes[i];
+//            final Class<?> arrayOfParamType = Array.newInstance(paramType, 0).getClass();
+//            final Class<?>[] returnTypes = { arrayOfParamType, List.class, Set.class, Collection.class };
+//            
+//            val autoCompleteMethod = findAutoCompleteNumMethodReturning(processMethodContext, i, returnTypes);
+//            if (autoCompleteMethod == null) {
+//                continue;
+//            }
+//            processMethodContext.removeMethod(autoCompleteMethod);
+//
+//            // add facets directly to parameters, not to actions
+//            final FacetedMethodParameter paramAsHolder = parameters.get(i);
+//            super.addFacet(
+//                    new ActionParameterAutoCompleteFacetViaMethod(
+//                            autoCompleteMethod, paramType, paramAsHolder));
+//        }
+//    }
+//
+//    private Method findAutoCompleteNumMethodReturning(
+//            final ProcessMethodContext processMethodContext,
+//            final int paramNum,
+//            final Class<?>[] returnTypes) {
+//
+//        final Class<?> cls = processMethodContext.getCls();
+//        final Method actionMethod = processMethodContext.getMethod();
+//        final String capitalizedName = StringExtensions.asCapitalizedName(actionMethod.getName());
+//        final String name = MethodLiteralConstants.AUTO_COMPLETE_PREFIX + paramNum + capitalizedName;
+//        return MethodFinderUtils.findMethod_returningAnyOf(
+//                returnTypes,
+//                cls,
+//                name,
+//                STRING_ARG);
+//    }
 
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/choices/methodnum/ActionParameterChoicesFacetViaMethod.java b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/choices/methodnum/ActionParameterChoicesFacetViaMethod.java
index 9bf1958..ebcad92 100644
--- a/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/choices/methodnum/ActionParameterChoicesFacetViaMethod.java
+++ b/core/metamodel/src/main/java/org/apache/isis/metamodel/facets/param/choices/methodnum/ActionParameterChoicesFacetViaMethod.java
@@ -44,8 +44,9 @@ implements ImperativeFacet {
 
     public ActionParameterChoicesFacetViaMethod(
             final Method method,
-            final Class<?> choicesType,
+            final Class<?> choicesType, 
             final FacetHolder holder) {
+        
         super(holder);
         this.method = method;
         this.choicesType = choicesType;
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 78f9b41..ea4ce37 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
@@ -19,25 +19,24 @@
 
 package org.apache.isis.metamodel.facets.param.choices.methodnum;
 
-import java.lang.reflect.Array;
-import java.lang.reflect.Method;
-import java.util.Collection;
 import java.util.List;
 
 import org.apache.isis.commons.collections.Can;
-import org.apache.isis.metamodel.commons.ListExtensions;
 import org.apache.isis.metamodel.commons.StringExtensions;
 import org.apache.isis.metamodel.exceptions.MetaModelException;
 import org.apache.isis.metamodel.facetapi.Facet;
 import org.apache.isis.metamodel.facetapi.FeatureType;
+import org.apache.isis.metamodel.facets.DependentArgUtils;
 import org.apache.isis.metamodel.facets.FacetedMethod;
 import org.apache.isis.metamodel.facets.FacetedMethodParameter;
-import org.apache.isis.metamodel.facets.MethodFinderUtils;
 import org.apache.isis.metamodel.facets.MethodLiteralConstants;
 import org.apache.isis.metamodel.facets.MethodPrefixBasedFacetFactoryAbstract;
 import org.apache.isis.metamodel.facets.param.choices.ActionChoicesFacet;
 
-public class ActionParameterChoicesFacetViaMethodFactory extends MethodPrefixBasedFacetFactoryAbstract {
+import lombok.val;
+
+public class ActionParameterChoicesFacetViaMethodFactory 
+extends MethodPrefixBasedFacetFactoryAbstract {
 
     private static final Can<String> PREFIXES = Can.empty();
 
@@ -63,81 +62,46 @@ public class ActionParameterChoicesFacetViaMethodFactory extends MethodPrefixBas
 
     }
 
-    private void attachChoicesFacetForParametersIfChoicesNumMethodIsFound(final ProcessMethodContext processMethodContext, final List<FacetedMethodParameter> parameters) {
+    private void attachChoicesFacetForParametersIfChoicesNumMethodIsFound(
+            final ProcessMethodContext processMethodContext, 
+            final List<FacetedMethodParameter> parameters) {
 
         if (parameters.isEmpty()) {
             return;
         }
 
-        final Method actionMethod = processMethodContext.getMethod();
-        final Class<?>[] paramTypes = actionMethod.getParameterTypes();
-
-        for (int i = 0; i < paramTypes.length; i++) {
+        val actionMethod = processMethodContext.getMethod();
+        val capitalizedName = StringExtensions.asCapitalizedName(actionMethod.getName());
 
-            final Class<?> arrayOfParamType = (Array.newInstance(paramTypes[i], 0)).getClass();
-
-            final Method choicesMethod = findChoicesNumMethodReturning(processMethodContext, i);
-            if (choicesMethod == null) {
-                continue;
-            }
+        val searchRequest = DependentArgUtils.ParamSupportingMethodSearchRequest.of(
+                processMethodContext, 
+                null,
+                paramIndex -> MethodLiteralConstants.CHOICES_PREFIX + paramIndex + capitalizedName);    
 
+        DependentArgUtils.findParamSupportingMethods(searchRequest, searchResult -> {
+            
+            val choicesMethod = searchResult.getSupportingMethod();
+            val paramIndex = searchResult.getParamIndex();
+            val returnType = searchResult.getReturnType();
+            
             processMethodContext.removeMethod(choicesMethod);
 
-            final FacetedMethod facetedMethod = processMethodContext.getFacetHolder();
+            val facetedMethod = processMethodContext.getFacetHolder();
             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");
+                val cls = processMethodContext.getCls();
+                throw new MetaModelException(cls + " uses both old and new choices syntax - "
+                        + "must use one or other");
             }
-
+            
             // add facets directly to parameters, not to actions
-            final FacetedMethodParameter paramAsHolder = parameters.get(i);
-            super.addFacet(new ActionParameterChoicesFacetViaMethod(choicesMethod, arrayOfParamType, paramAsHolder));
-        }
+            val paramAsHolder = parameters.get(paramIndex);
+            super.addFacet(
+                    new ActionParameterChoicesFacetViaMethod(
+                            choicesMethod, returnType, paramAsHolder));
+        });
+        
     }
-
-    /**
-     * search successively for the default method, trimming number of param types each loop
-     */
-    private static Method findChoicesNumMethodReturning(final ProcessMethodContext processMethodContext, final int n) {
-
-        final Method actionMethod = processMethodContext.getMethod();
-        final List<Class<?>> paramTypes = ListExtensions.mutableCopy(actionMethod.getParameterTypes());
-
-        final Class<?> arrayOfParamType = (Array.newInstance(paramTypes.get(n), 0)).getClass();
-
-        final int numParamTypes = paramTypes.size();
-
-        for(int i=0; i< numParamTypes+1; i++) {
-            Method method;
-
-            method = findChoicesNumMethodReturning(processMethodContext, n, paramTypes.toArray(new Class<?>[]{}), arrayOfParamType);
-            if(method != null) {
-                return method;
-            }
-            method = findChoicesNumMethodReturning(processMethodContext, n, paramTypes.toArray(new Class<?>[]{}), Collection.class);
-            if(method != null) {
-                return method;
-            }
-
-            // remove last, and search again
-            if(!paramTypes.isEmpty()) {
-                paramTypes.remove(paramTypes.size()-1);
-            }
-        }
-
-        return null;
-    }
-
-
-
-    private static Method findChoicesNumMethodReturning(final ProcessMethodContext processMethodContext, final int n, Class<?>[] paramTypes, final Class<?> returnType) {
-        final Class<?> cls = processMethodContext.getCls();
-        final Method actionMethod = processMethodContext.getMethod();
-        final String capitalizedName = StringExtensions.asCapitalizedName(actionMethod.getName());
-        final String name = MethodLiteralConstants.CHOICES_PREFIX + n + capitalizedName;
-        return MethodFinderUtils.findMethod(cls, name, returnType, paramTypes);
-    }
-
-
+    
+    
 
 }
diff --git a/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/actions/ActionMethodsFacetFactoryTest.java b/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/actions/ActionMethodsFacetFactoryTest.java
index 193b5ba..3446a7a 100644
--- a/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/actions/ActionMethodsFacetFactoryTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/metamodel/facets/actions/ActionMethodsFacetFactoryTest.java
@@ -19,14 +19,14 @@
 
 package org.apache.isis.metamodel.facets.actions;
 
-import lombok.val;
-
 import java.lang.reflect.Method;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
+import org.jmock.Expectations;
+
 import org.apache.isis.metamodel.facetapi.Facet;
 import org.apache.isis.metamodel.facets.AbstractFacetFactoryTest;
 import org.apache.isis.metamodel.facets.FacetFactory.ProcessMethodContext;
@@ -53,7 +53,8 @@ import org.apache.isis.metamodel.spec.ObjectSpecification;
 import org.apache.isis.metamodel.testspec.ObjectSpecificationStub;
 import org.apache.isis.security.api.authentication.AuthenticationSession;
 import org.apache.isis.unittestsupport.jmocking.JUnitRuleMockery2;
-import org.jmock.Expectations;
+
+import lombok.val;
 
 public class ActionMethodsFacetFactoryTest extends AbstractFacetFactoryTest {
 
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 897ade8..0329728 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
@@ -39,6 +39,7 @@ import org.apache.isis.metamodel.testspec.ObjectSpecificationStub;
 
 import lombok.val;
 
+@SuppressWarnings("unused")
 public class ActionAnnotationFacetFactoryTest_ActionInvocation extends AbstractFacetFactoryTest {
 
     private final ObjectSpecification voidSpec = new ObjectSpecificationStub("VOID");
@@ -65,7 +66,6 @@ public class ActionAnnotationFacetFactoryTest_ActionInvocation extends AbstractF
         allowing_specificationLoader_loadSpecification_any_willReturn(voidSpec);
 
         class Customer {
-            @SuppressWarnings("unused")
             public void someAction() {
             }
         }
@@ -87,7 +87,6 @@ public class ActionAnnotationFacetFactoryTest_ActionInvocation extends AbstractF
         allowing_specificationLoader_loadSpecification_any_willReturn(voidSpec);
 
         class Customer {
-            @SuppressWarnings("unused")
             public void someAction() {
             }
         }
@@ -105,7 +104,6 @@ public class ActionAnnotationFacetFactoryTest_ActionInvocation extends AbstractF
         allowing_specificationLoader_loadSpecification_any_willReturn(stringSpec);
 
         class Customer {
-            @SuppressWarnings("unused")
             public String someAction() {
                 return null;
             }
@@ -124,7 +122,6 @@ public class ActionAnnotationFacetFactoryTest_ActionInvocation extends AbstractF
         allowing_specificationLoader_loadSpecification_any_willReturn(customerSpec);
 
         class Customer {
-            @SuppressWarnings("unused")
             public String someAction() {
                 return null;
             }
@@ -143,7 +140,6 @@ public class ActionAnnotationFacetFactoryTest_ActionInvocation extends AbstractF
         allowing_specificationLoader_loadSpecification_any_willReturn(voidSpec);
 
         class Customer {
-            @SuppressWarnings("unused")
             public void someAction(final int x, final long y) {
             }
         }
@@ -173,11 +169,11 @@ public class ActionAnnotationFacetFactoryTest_ActionInvocation extends AbstractF
         
         
         class Customer {
-            @SuppressWarnings("unused")
+            
             public void someAction(final int x, final long y) {
             }
 
-            @SuppressWarnings("unused")
+            
             public int[] choices0SomeAction() {
                 return new int[0];
             }
@@ -189,12 +185,12 @@ public class ActionAnnotationFacetFactoryTest_ActionInvocation extends AbstractF
                 return new int[0];
             }
 
-            @SuppressWarnings("unused")
+            
             public long[] choices1SomeAction() {
                 return new long[0];
             }
 
-            @SuppressWarnings("unused")
+            
             public String disableSomeAction(final int x, final long y) {
                 return null;
             }
diff --git a/examples/demo/src/main/java/demoapp/dom/actions/depargs/DependentArgsActionDemo_useAutoComplete.java b/examples/demo/src/main/java/demoapp/dom/actions/depargs/DependentArgsActionDemo_useAutoComplete.java
index a0a2523..c8f1bbf 100644
--- a/examples/demo/src/main/java/demoapp/dom/actions/depargs/DependentArgsActionDemo_useAutoComplete.java
+++ b/examples/demo/src/main/java/demoapp/dom/actions/depargs/DependentArgsActionDemo_useAutoComplete.java
@@ -64,7 +64,7 @@ public class DependentArgsActionDemo_useAutoComplete {
 
     // -- PARAM 1 (DemoItem)
 
-    //@Supporting
+    @Model
     public Collection<DemoItem> autoComplete1$$(
 
             Parity parity, // <-- the refining parameter from the dialog above
diff --git a/examples/demo/src/main/java/demoapp/dom/actions/depargs/DependentArgsActionDemo_useChoices.java b/examples/demo/src/main/java/demoapp/dom/actions/depargs/DependentArgsActionDemo_useChoices.java
index b9ee525..de35418 100644
--- a/examples/demo/src/main/java/demoapp/dom/actions/depargs/DependentArgsActionDemo_useChoices.java
+++ b/examples/demo/src/main/java/demoapp/dom/actions/depargs/DependentArgsActionDemo_useChoices.java
@@ -63,7 +63,7 @@ public class DependentArgsActionDemo_useChoices {
 
     // -- PARAM 1 (DemoItem)
 
-    //@Supporting
+    @Model
     public Collection<DemoItem> choices1$$(
             
             Parity parity // <-- the refining parameter from the dialog above
diff --git a/examples/demo/src/main/java/demoapp/dom/actions/depargs/DependentArgsActionDemo_useDefault.java b/examples/demo/src/main/java/demoapp/dom/actions/depargs/DependentArgsActionDemo_useDefault.java
index d9de12c..d8917f3 100644
--- a/examples/demo/src/main/java/demoapp/dom/actions/depargs/DependentArgsActionDemo_useDefault.java
+++ b/examples/demo/src/main/java/demoapp/dom/actions/depargs/DependentArgsActionDemo_useDefault.java
@@ -63,7 +63,7 @@ public class DependentArgsActionDemo_useDefault {
 
     // -- PARAM 1 (String message)
 
-    //@Supporting
+    @Model
     public String default1$$(Parity parity) {
         if(parity == null) {
             return "no parity selected";
diff --git a/examples/demo/src/main/java/demoapp/dom/actions/depargs/DependentArgsActionDemo_useDisable.java b/examples/demo/src/main/java/demoapp/dom/actions/depargs/DependentArgsActionDemo_useDisable.java
index 5626209..f10e056 100644
--- a/examples/demo/src/main/java/demoapp/dom/actions/depargs/DependentArgsActionDemo_useDisable.java
+++ b/examples/demo/src/main/java/demoapp/dom/actions/depargs/DependentArgsActionDemo_useDisable.java
@@ -62,7 +62,7 @@ public class DependentArgsActionDemo_useDisable {
 
     // -- PARAM 1 (String message)
 
-    //@Supporting
+    //@Model //TODO waits for dep args to be implemented
     public String disable1$$(boolean disableMessageField) {
         return disableMessageField
                 ? "disabled by dependent argument"
diff --git a/examples/demo/src/main/java/demoapp/dom/actions/depargs/DependentArgsActionDemo_useHide.java b/examples/demo/src/main/java/demoapp/dom/actions/depargs/DependentArgsActionDemo_useHide.java
index f6f7e7a..5cb5cf8 100644
--- a/examples/demo/src/main/java/demoapp/dom/actions/depargs/DependentArgsActionDemo_useHide.java
+++ b/examples/demo/src/main/java/demoapp/dom/actions/depargs/DependentArgsActionDemo_useHide.java
@@ -62,7 +62,7 @@ public class DependentArgsActionDemo_useHide {
 
     // -- PARAM 1 (String message)
 
-    //@Supporting
+    //@Model //TODO waits for dep args to be implemented
     public boolean hide1$$(boolean hideMessageField) {
         return hideMessageField;
     }
diff --git a/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberSupport.java b/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberSupport.java
index 9a0dcf6..fce1563 100644
--- a/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberSupport.java
+++ b/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberSupport.java
@@ -85,15 +85,21 @@ public class ProperMemberSupport {
     }
     
     @Model
-    public Set<String> choices0MyAction(String p0) {
+    public Set<String> choices0MyAction() {
         return null;
     }
 
     @Model
-    public Set<String> choices1MyAction(String p0) {
+    public Set<String> choices1MyAction() {
         return null;
     }
     
+// variant with dependent arg
+//    @Model
+//    public Set<String> choices1MyAction(String p0) {
+//        return null;
+//    }
+    
     @Model
     public String default0MyAction() {
         return null;
diff --git a/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberSupport_action2.java b/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberSupport_action2.java
index 2a8544a..22c9ed4 100644
--- a/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberSupport_action2.java
+++ b/examples/smoketests/src/main/java/org/apache/isis/testdomain/model/good/ProperMemberSupport_action2.java
@@ -62,16 +62,28 @@ public class ProperMemberSupport_action2 {
     public Set<String> autoComplete1$$(@MinLength(3) String search) {
         return null;
     }
+
+// variant with dependent arg
+//    @Model
+//    public Set<String> autoComplete1$$(String p0, @MinLength(3) String search) {
+//        return null;
+//    }
     
     @Model
-    public Set<String> choices0$$(String p0) {
+    public Set<String> choices0$$() {
         return null;
     }
 
     @Model
-    public Set<String> choices1$$(String p0) {
+    public Set<String> choices1$$() {
         return null;
     }
+
+// variant with dependent arg    
+//    @Model 
+//    public Set<String> choices1$$(String p0) {
+//        return null;
+//    }
     
     @Model
     public String default0$$() {