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 2021/09/08 08:37:36 UTC

[isis] branch master updated: ISIS-2774: method finder overhaul

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 c507416  ISIS-2774: method finder overhaul
c507416 is described below

commit c5074166ecb4c617a124d1e110507fd1d592294b
Author: Andi Huber <ah...@apache.org>
AuthorDate: Wed Sep 8 10:37:27 2021 +0200

    ISIS-2774: method finder overhaul
---
 .../org/apache/isis/commons/collections/Can.java   |   4 +-
 .../apache/isis/commons/collections/Can_Empty.java |   4 +-
 .../isis/commons/collections/Can_Multiple.java     |   4 +-
 .../isis/commons/collections/Can_Singleton.java    |   4 +-
 .../apache/isis/commons/collections/CanTest.java   |  20 +-
 .../DomainObjectAnnotationFacetFactory.java        |   2 +-
 .../recreatable/RecreatableObjectFacetFactory.java |   2 +-
 .../annotation/TitleAnnotationFacetFactory.java    |   2 +-
 .../isis/core/metamodel/methods/MethodFinder.java  |  86 +++-----
 .../metamodel/methods/MethodFinderOptions.java     |  66 +++++-
 .../core/metamodel/methods/MethodFinderUtils.java  | 241 +--------------------
 .../metamodel/facets/MethodFinderUtilsTest.java    |   6 +-
 .../restfulobjects/viewer/mappers/FailureUtil.java |  12 +-
 13 files changed, 136 insertions(+), 317 deletions(-)

diff --git a/commons/src/main/java/org/apache/isis/commons/collections/Can.java b/commons/src/main/java/org/apache/isis/commons/collections/Can.java
index 5c1e293..d252f2d 100644
--- a/commons/src/main/java/org/apache/isis/commons/collections/Can.java
+++ b/commons/src/main/java/org/apache/isis/commons/collections/Can.java
@@ -361,14 +361,14 @@ extends Iterable<T>, Comparable<Can<T>>, Serializable {
      * {@link Object#equals(Object)} object equality.
      * @return non-null
      */
-    public Can<T> unique();
+    public Can<T> distinct();
 
     /**
      * Returns a {@code Can} with all the elements from this {@code Can}, but
      * duplicated elements removed, based on given {@code equality} relation.
      * @return non-null
      */
-    public Can<T> unique(@NonNull BiPredicate<T, T> equality);
+    public Can<T> distinct(@NonNull BiPredicate<T, T> equality);
 
     /**
      * Returns a {@code Can} with all the elements from this {@code Can}, but
diff --git a/commons/src/main/java/org/apache/isis/commons/collections/Can_Empty.java b/commons/src/main/java/org/apache/isis/commons/collections/Can_Empty.java
index 6fa3786..e86b6ef 100644
--- a/commons/src/main/java/org/apache/isis/commons/collections/Can_Empty.java
+++ b/commons/src/main/java/org/apache/isis/commons/collections/Can_Empty.java
@@ -102,12 +102,12 @@ final class Can_Empty<T> implements Can<T> {
     }
 
     @Override
-    public Can<T> unique() {
+    public Can<T> distinct() {
         return this;
     }
 
     @Override
-    public Can<T> unique(final @NonNull BiPredicate<T, T> equality) {
+    public Can<T> distinct(final @NonNull BiPredicate<T, T> equality) {
         return this;
     }
 
diff --git a/commons/src/main/java/org/apache/isis/commons/collections/Can_Multiple.java b/commons/src/main/java/org/apache/isis/commons/collections/Can_Multiple.java
index a2d7bba..761c8b9 100644
--- a/commons/src/main/java/org/apache/isis/commons/collections/Can_Multiple.java
+++ b/commons/src/main/java/org/apache/isis/commons/collections/Can_Multiple.java
@@ -115,14 +115,14 @@ final class Can_Multiple<T> implements Can<T> {
     }
 
     @Override
-    public Can<T> unique() {
+    public Can<T> distinct() {
         val set = new LinkedHashSet<T>(); // preserve order
         set.addAll(elements);
         return Can.ofCollection(set);
     }
 
     @Override
-    public Can<T> unique(final @NonNull BiPredicate<T, T> equality) {
+    public Can<T> distinct(final @NonNull BiPredicate<T, T> equality) {
         final int initialSize = Math.min(1024, elements.size());
         val uniqueElements = _Lists.<T>newArrayList(initialSize);
         elements
diff --git a/commons/src/main/java/org/apache/isis/commons/collections/Can_Singleton.java b/commons/src/main/java/org/apache/isis/commons/collections/Can_Singleton.java
index 72b26c9..67c4464 100644
--- a/commons/src/main/java/org/apache/isis/commons/collections/Can_Singleton.java
+++ b/commons/src/main/java/org/apache/isis/commons/collections/Can_Singleton.java
@@ -103,12 +103,12 @@ final class Can_Singleton<T> implements Can<T> {
     }
 
     @Override
-    public Can<T> unique() {
+    public Can<T> distinct() {
         return this;
     }
 
     @Override
-    public Can<T> unique(final @NonNull BiPredicate<T, T> equality) {
+    public Can<T> distinct(final @NonNull BiPredicate<T, T> equality) {
         return this;
     }
 
diff --git a/commons/src/test/java/org/apache/isis/commons/collections/CanTest.java b/commons/src/test/java/org/apache/isis/commons/collections/CanTest.java
index b07344c..d07590a 100644
--- a/commons/src/test/java/org/apache/isis/commons/collections/CanTest.java
+++ b/commons/src/test/java/org/apache/isis/commons/collections/CanTest.java
@@ -195,23 +195,23 @@ class CanTest {
 
         assertEquals(
                 Can.empty(),
-                Can.empty().unique());
+                Can.empty().distinct());
 
         assertEquals(
                 Can.of("a"),
-                Can.of("a").unique());
+                Can.of("a").distinct());
 
         assertEquals(
                 Can.of("a"),
-                Can.of("a", "a", "a").unique());
+                Can.of("a", "a", "a").distinct());
 
         assertEquals(
                 Can.of("a", "b", "c"),
-                Can.of("a", "b", "c").unique());
+                Can.of("a", "b", "c").distinct());
 
         assertEquals(
                 Can.of("a", "b"),
-                Can.of("a", "b", "a").unique());
+                Can.of("a", "b", "a").distinct());
     }
 
     @Test
@@ -222,23 +222,23 @@ class CanTest {
 
         assertEquals(
                 Can.empty(),
-                Can.<String>empty().unique(firstCharEquility));
+                Can.<String>empty().distinct(firstCharEquility));
 
         assertEquals(
                 Can.of("a"),
-                Can.of("a").unique(firstCharEquility));
+                Can.of("a").distinct(firstCharEquility));
 
         assertEquals(
                 Can.of("aDog"),
-                Can.of("aDog", "aCat", "aMonkey").unique(firstCharEquility));
+                Can.of("aDog", "aCat", "aMonkey").distinct(firstCharEquility));
 
         assertEquals(
                 Can.of("aDog", "bCat", "cMonkey"),
-                Can.of("aDog", "bCat", "cMonkey").unique(firstCharEquility));
+                Can.of("aDog", "bCat", "cMonkey").distinct(firstCharEquility));
 
         assertEquals(
                 Can.of("aDog", "bCat"),
-                Can.of("aDog", "bCat", "aMonkey").unique(firstCharEquility));
+                Can.of("aDog", "bCat", "aMonkey").distinct(firstCharEquility));
 
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
index c085e33..16db365 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/domainobject/DomainObjectAnnotationFacetFactory.java
@@ -646,7 +646,7 @@ implements
     public Method postConstructMethodFor(final Object pojo) {
         return MethodFinderUtils.findAnnotatedMethod(
                 // @PostConstruct is allowed to appear on non-public methods
-                MethodFinderOptions.notNecessarilyPublic(),
+                MethodFinderOptions.notNecessarilyPublic(MethodFinderOptions.ANY_NAME),
                 pojo, PostConstruct.class, postConstructMethodsCache);
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetFactory.java
index ca43a5e..f7c3ed6 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/recreatable/RecreatableObjectFacetFactory.java
@@ -131,7 +131,7 @@ implements
     public Method postConstructMethodFor(final Object pojo) {
         return MethodFinderUtils.findAnnotatedMethod(
                 // @PostConstruct is allowed to appear on non-public methods
-                MethodFinderOptions.notNecessarilyPublic(),
+                MethodFinderOptions.notNecessarilyPublic(MethodFinderOptions.ANY_NAME),
                 pojo, PostConstruct.class, postConstructMethodsCache);
     }
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/annotation/TitleAnnotationFacetFactory.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/annotation/TitleAnnotationFacetFactory.java
index a4fa539..fc3418e 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/annotation/TitleAnnotationFacetFactory.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/title/annotation/TitleAnnotationFacetFactory.java
@@ -75,7 +75,7 @@ implements MetaModelRefiner {
                 .getFacetRanking(TitleFacet.class)
                 .map(facetRanking->facetRanking.getTopRank(TitleFacet.class))
                 .orElse(Can.empty())
-                .unique(TitleFacet::semanticEquals);
+                .distinct(TitleFacet::semanticEquals);
 
             // top-rank if present must not be ambiguous
             if(titleFacetTopRank.isCardinalityMultiple()) {
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodFinder.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodFinder.java
index aced3b3..276cb08 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodFinder.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodFinder.java
@@ -19,10 +19,10 @@
 package org.apache.isis.core.metamodel.methods;
 
 import java.lang.reflect.Method;
+import java.util.function.Predicate;
 import java.util.stream.Stream;
 
 import org.apache.isis.commons.collections.Can;
-import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.core.config.progmodel.ProgrammingModelConstants.ReturnTypeCategory;
 import org.apache.isis.core.metamodel.methods.MethodFinderUtils.MethodAndPpmConstructor;
 
@@ -33,17 +33,23 @@ import org.apache.isis.core.metamodel.methods.MethodFinderUtils.MethodAndPpmCons
 //@Log4j2
 public final class MethodFinder {
 
+    public static Predicate<Method> hasReturnType(final Class<?> expectedReturnType) {
+        return method->expectedReturnType.isAssignableFrom(method.getReturnType());
+    }
+
+    public static Predicate<Method> hasReturnTypeAnyOf(final Can<Class<?>> allowedReturnTypes) {
+        return method->allowedReturnTypes.stream()
+                .anyMatch(allowedReturnType->allowedReturnType.isAssignableFrom(method.getReturnType()));
+    }
+
     public static Stream<Method> findMethod(
             final MethodFinderOptions options,
             final Class<?> type,
             final Class<?> expectedReturnType,
             final Class<?>[] paramTypes) {
 
-        return options.getMethodNameCandidates().stream()
-        .distinct()
-        .map(name->MethodFinderUtils
-                .findMethod(options, type, name, expectedReturnType, paramTypes))
-        .filter(_NullSafe::isPresent);
+        return options.streamMethods(type, paramTypes)
+                .filter(hasReturnType(expectedReturnType));
     }
 
     // -- SEARCH FOR MULTIPLE NAME CANDIDATES
@@ -54,11 +60,8 @@ public final class MethodFinder {
             final Class<?> type,
             final Class<?>[] paramTypes) {
 
-        return options.getMethodNameCandidates().stream()
-        .distinct()
-        .map(name->MethodFinderUtils
-                .findMethod_returningCategory(options, returnTypeCategory, type, name, paramTypes))
-        .filter(_NullSafe::isPresent);
+        return options.streamMethods(type, paramTypes)
+                .filter(hasReturnTypeAnyOf(returnTypeCategory.getReturnTypes()));
     }
 
     public static Stream<Method> findMethod_returningBoolean(
@@ -66,11 +69,7 @@ public final class MethodFinder {
             final Class<?> type,
             final Class<?>[] paramTypes) {
 
-        return options.getMethodNameCandidates().stream()
-        .distinct()
-        .map(name->MethodFinderUtils
-                .findMethod_returningBoolean(options, type, name, paramTypes))
-        .filter(_NullSafe::isPresent);
+        return findMethod_returningCategory(options, ReturnTypeCategory.BOOLEAN, type, paramTypes);
     }
 
     public static Stream<Method> findMethod_returningText(
@@ -78,11 +77,7 @@ public final class MethodFinder {
             final Class<?> type,
             final Class<?>[] paramTypes) {
 
-        return options.getMethodNameCandidates().stream()
-        .distinct()
-        .map(name->MethodFinderUtils
-                .findMethod_returningText(options, type, name, paramTypes))
-        .filter(_NullSafe::isPresent);
+        return findMethod_returningCategory(options, ReturnTypeCategory.TRANSLATABLE, type, paramTypes);
     }
 
     public static Stream<Method> findMethod_returningNonScalar(
@@ -91,15 +86,13 @@ public final class MethodFinder {
             final Class<?> elementReturnType,
             final Class<?>[] paramTypes) {
 
-        return options.getMethodNameCandidates().stream()
-        .distinct()
-        .map(name->MethodFinderUtils
-                .findMethod_returningNonScalar(options, type, name, elementReturnType, paramTypes))
-        .filter(_NullSafe::isPresent);
+        return options.streamMethods(type, paramTypes)
+                .filter(hasReturnTypeAnyOf(ReturnTypeCategory.nonScalar(elementReturnType)));
     }
 
     // -- SEARCH FOR MULTIPLE NAME CANDIDATES (PPM)
 
+    @Deprecated // redundant
     public static Stream<MethodAndPpmConstructor> findMethodWithPPMArg(
             final MethodFinderOptions options,
             final Class<?> type,
@@ -107,13 +100,11 @@ public final class MethodFinder {
             final Class<?>[] paramTypes,
             final Can<Class<?>> additionalParamTypes) {
 
-        return options.getMethodNameCandidates().stream()
-        .distinct()
-        .map(name->MethodFinderUtils
-                .findMethodWithPPMArg(options, type, name, returnType, paramTypes, additionalParamTypes))
-        .filter(_NullSafe::isPresent);
+        return MethodFinderUtils
+                .findMethodWithPPMArg(options, type, returnType, paramTypes, additionalParamTypes);
     }
 
+    @Deprecated // redundant
     public static Stream<MethodAndPpmConstructor> findMethodWithPPMArg_returningAnyOf(
             final MethodFinderOptions options,
             final Can<Class<?>> returnTypes,
@@ -121,11 +112,9 @@ public final class MethodFinder {
             final Class<?>[] paramTypes,
             final Can<Class<?>> additionalParamTypes) {
 
-        return options.getMethodNameCandidates().stream()
-        .distinct()
-        .map(name->MethodFinderUtils
-                .findMethodWithPPMArg_returningAnyOf(options, returnTypes, type, name, paramTypes, additionalParamTypes))
-        .filter(_NullSafe::isPresent);
+        return MethodFinderUtils
+                .findMethodWithPPMArg_returningAnyOf(
+                        options, returnTypes, type, paramTypes, additionalParamTypes);
     }
 
     public static Stream<MethodAndPpmConstructor> findMethodWithPPMArg_returningBoolean(
@@ -134,11 +123,9 @@ public final class MethodFinder {
             final Class<?>[] paramTypes,
             final Can<Class<?>> additionalParamTypes) {
 
-        return options.getMethodNameCandidates().stream()
-        .distinct()
-        .map(name->MethodFinderUtils
-                .findMethodWithPPMArg_returningBoolean(options, type, name, paramTypes, additionalParamTypes))
-        .filter(_NullSafe::isPresent);
+        return MethodFinderUtils
+        .findMethodWithPPMArg_returningAnyOf(
+                options, ReturnTypeCategory.BOOLEAN.getReturnTypes(), type, paramTypes, additionalParamTypes);
     }
 
     public static Stream<MethodAndPpmConstructor> findMethodWithPPMArg_returningText(
@@ -147,11 +134,9 @@ public final class MethodFinder {
             final Class<?>[] paramTypes,
             final Can<Class<?>> additionalParamTypes) {
 
-        return options.getMethodNameCandidates().stream()
-        .distinct()
-        .map(name->MethodFinderUtils
-                .findMethodWithPPMArg_returningText(options, type, name, paramTypes, additionalParamTypes))
-        .filter(_NullSafe::isPresent);
+        return MethodFinderUtils
+        .findMethodWithPPMArg_returningAnyOf(
+                options, ReturnTypeCategory.TRANSLATABLE.getReturnTypes(), type, paramTypes, additionalParamTypes);
     }
 
     public static Stream<MethodAndPpmConstructor> findMethodWithPPMArg_returningNonScalar(
@@ -161,12 +146,9 @@ public final class MethodFinder {
             final Class<?>[] paramTypes,
             final Can<Class<?>> additionalParamTypes) {
 
-        return options.getMethodNameCandidates().stream()
-        .distinct()
-        .map(name->MethodFinderUtils
-                .findMethodWithPPMArg_returningNonScalar(options, type, name, elementReturnType, paramTypes, additionalParamTypes))
-        .filter(_NullSafe::isPresent);
+        return MethodFinderUtils
+        .findMethodWithPPMArg_returningAnyOf(
+                options, ReturnTypeCategory.nonScalar(elementReturnType), type, paramTypes, additionalParamTypes);
     }
 
-
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodFinderOptions.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodFinderOptions.java
index 347a27c..8701091 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodFinderOptions.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodFinderOptions.java
@@ -21,27 +21,55 @@ package org.apache.isis.core.metamodel.methods;
 import java.lang.annotation.Annotation;
 import java.lang.reflect.Method;
 import java.util.function.Predicate;
+import java.util.stream.Stream;
 
 import org.apache.isis.applib.annotation.Domain;
 import org.apache.isis.applib.annotation.Introspection.EncapsulationPolicy;
 import org.apache.isis.applib.annotation.Introspection.IntrospectionPolicy;
 import org.apache.isis.commons.collections.Can;
+import org.apache.isis.commons.internal.base._NullSafe;
 import org.apache.isis.commons.internal.functions._Predicates;
 import org.apache.isis.commons.internal.reflection._Annotations;
+import org.apache.isis.commons.internal.reflection._ClassCache;
 import org.apache.isis.commons.internal.reflection._Reflect;
 import org.apache.isis.core.config.progmodel.ProgrammingModelConstants;
 import org.apache.isis.core.config.progmodel.ProgrammingModelConstants.ConflictingAnnotations;
+import org.apache.isis.core.metamodel.commons.MethodUtil;
 
+import lombok.AccessLevel;
+import lombok.Getter;
 import lombok.NonNull;
-import lombok.Value;
+import lombok.RequiredArgsConstructor;
 import lombok.val;
 
-@Value(staticConstructor = "of")
+@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
 public class MethodFinderOptions {
 
-    public static MethodFinderOptions notNecessarilyPublic() {
+    public static MethodFinderOptions of(
+            @NonNull final Can<String> methodNameCandidatesPossiblyDuplicated,
+            @NonNull final EncapsulationPolicy encapsulationPolicy,
+            @NonNull final Predicate<Method> mustSatisfy) {
+
+        final Predicate<Method> isNotStatic = MethodUtil::isNotStatic;
+        val methodNameCandidates = methodNameCandidatesPossiblyDuplicated.distinct();
+
+        return new MethodFinderOptions(
+                encapsulationPolicy,
+                methodNameCandidates.equals(ANY_NAME)
+                        ? isNotStatic.and(mustSatisfy)
+                        : isNotStatic
+                            .and(method->methodNameCandidates.contains(method.getName()))
+                            .and(mustSatisfy),
+                methodNameCandidates.distinct());
+    }
+
+    public static final Can<String> ANY_NAME = Can.of("");
+    public static final Class<?>[] NO_ARG = new Class<?>[0];
+
+    public static MethodFinderOptions notNecessarilyPublic(
+            final Can<String> methodNameCandidates) {
         return of(
-                Can.empty(), //FIXME
+                methodNameCandidates,
                 EncapsulationPolicy.ENCAPSULATED_MEMBERS_SUPPORTED,
                 _Predicates.alwaysTrue()
                 );
@@ -94,9 +122,33 @@ public class MethodFinderOptions {
                 ProgrammingModelConstants.ConflictingAnnotations.MEMBER_SUPPORT);
     }
 
+    @Getter private final @NonNull EncapsulationPolicy encapsulationPolicy;
+    @Getter private final @NonNull Predicate<Method> mustSatisfy;
     private final @NonNull Can<String> methodNameCandidates;
-    private final @NonNull EncapsulationPolicy encapsulationPolicy;
-    private final @NonNull Predicate<Method> mustSatisfy;
+
+    public Stream<Method> streamMethods(
+            final Class<?> type,
+            final Class<?>[] paramTypes) {
+
+        val classCache = _ClassCache.getInstance();
+        val isEncapsulationSupported = getEncapsulationPolicy().isEncapsulatedMembersSupported();
+
+        if(methodNameCandidates.equals(ANY_NAME)) {
+            //stream all
+            return (isEncapsulationSupported
+                    ? classCache.streamPublicOrDeclaredMethods(type)
+                    : classCache.streamPublicMethods(type))
+                        .filter(mustSatisfy);
+        }
+
+        return methodNameCandidates.stream()
+        .map(name->isEncapsulationSupported
+                ? classCache.lookupPublicOrDeclaredMethod(type, name, paramTypes)
+                : classCache.lookupPublicMethod(type, name, paramTypes))
+        .filter(_NullSafe::isPresent)
+        .filter(mustSatisfy);
+
+    }
 
     // -- HELPER
 
@@ -165,4 +217,6 @@ public class MethodFinderOptions {
     }
 
 
+
+
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodFinderUtils.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodFinderUtils.java
index 4dcadc0..0aa9d9d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodFinderUtils.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/methods/MethodFinderUtils.java
@@ -28,9 +28,7 @@ import java.util.stream.Stream;
 import org.apache.isis.commons.collections.Can;
 import org.apache.isis.commons.internal.reflection._ClassCache;
 import org.apache.isis.commons.internal.reflection._Reflect;
-import org.apache.isis.core.config.progmodel.ProgrammingModelConstants.ReturnTypeCategory;
 import org.apache.isis.core.metamodel.commons.MethodUtil;
-import org.apache.isis.core.metamodel.facetapi.MethodRemover;
 
 import static org.apache.isis.commons.internal.reflection._Reflect.Filter.paramSignatureMatch;
 
@@ -45,114 +43,14 @@ public final class MethodFinderUtils {
     private MethodFinderUtils() {
     }
 
-    /**
-     * Returns a specific public methods that: have the specified prefix; have
-     * the specified return type (or some subtype), and has the
-     * specified number of parameters.
-     *
-     * <p>
-     * If the returnType is specified as null then the return type is ignored.
-     * If void.class is passed in, then searches for void methods.
-     *
-     * <p>
-     * If the parameter type array is null, is also not checked.
-     */
-    public static Method findMethod(
+    private static Stream<Method> streamMethods(
             final MethodFinderOptions options,
             final Class<?> type,
-            final String name,
-            final Class<?> expectedReturnType,
-            final Class<?>[] paramTypes) {
-
-        val classCache = _ClassCache.getInstance();
-
-        val method = options.getEncapsulationPolicy().isEncapsulatedMembersSupported()
-                ? classCache.lookupPublicOrDeclaredMethod(type, name, paramTypes)
-                : classCache.lookupPublicMethod(type, name, paramTypes);
-        if(method == null) {
-            return null;
-        }
-
-        if(!options.getEncapsulationPolicy().isEncapsulatedMembersSupported()) {
-            if (!MethodUtil.isPublic(method)) {
-                return null;
-            }
-        }
-
-        if(MethodUtil.isStatic(method)) {
-            return null;
-        }
-
-        if (!method.getName().equals(name)) {
-            return null;
-        }
-
-        if (expectedReturnType != null && !expectedReturnType.isAssignableFrom(method.getReturnType())) {
-            return null;
-        }
-
-        if (paramTypes != null) {
-            val parameterTypes = method.getParameterTypes();
-            if (paramTypes.length != parameterTypes.length) {
-                return null;
-            }
-
-            for (int c = 0; c < paramTypes.length; c++) {
-                if ((paramTypes[c] != null) && (paramTypes[c] != parameterTypes[c])) {
-                    return null;
-                }
-            }
-        }
-
-        if(!options.getMustSatisfy().test(method)) {
-            return null;
-        }
-
-        return method;
-    }
-
-    public static Method findMethod_returningAnyOf(
-            final MethodFinderOptions options,
-            final Can<Class<?>> returnTypes,
-            final Class<?> type,
-            final String name,
-            final Class<?>[] paramTypes) {
-
-        for (val returnType : returnTypes) {
-            val method = findMethod(options, type, name, returnType, paramTypes);
-            if(method != null) {
-                return method;
-            }
-        }
-        return null;
-    }
-
-    public static Optional<Method> findNoArgMethod(
-            final MethodFinderOptions options,
-            final Class<?> type, final Class<?> returnType) {
-        return streamMethods(options, type, options.getMethodNameCandidates(), returnType)
-                .filter(MethodUtil.Predicates.paramCount(0))
-                .findFirst();
-    }
-
-    public static Optional<Method> findSingleArgMethod(
-            final MethodFinderOptions options,
-            final Class<?> type, final String name, final Class<?> returnType) {
-        return streamMethods(options, type, Can.ofSingleton(name), returnType)
-                .filter(MethodUtil.Predicates.paramCount(1))
-                .findFirst();
-    }
-
-    public static Stream<Method> streamMethods(
-            final MethodFinderOptions options,
-            final Class<?> type,
-            final Can<String> names,
             final Class<?> returnType) {
         try {
 
             return streamMethods(options, type)
-                    .filter(MethodUtil::isNotStatic)
-                    .filter(method -> names.contains(method.getName()))
+                    .filter(options.getMustSatisfy())
                     .filter(method -> returnType == null
                             || returnType.isAssignableFrom(method.getReturnType())
 //XXX for non-scalar types we should probably be a bit smarter
@@ -165,38 +63,6 @@ public final class MethodFinderUtils {
         }
     }
 
-    public static Stream<Method> streamMethodsWithAnnotation(
-            final @NonNull MethodFinderOptions options,
-            final @NonNull Class<?> type,
-            final @NonNull Class<? extends Annotation> annotationClass) {
-
-        // Find methods annotated with the specified annotation
-        return streamMethods(options, type)
-                .filter(method -> !MethodUtil.isStatic(method))
-                .filter(method -> method.isAnnotationPresent(annotationClass));
-    }
-
-    public static void removeMethod(final MethodRemover methodRemover, final Method method) {
-        if (methodRemover != null && method != null) {
-            methodRemover.removeMethod(method);
-        }
-    }
-
-    public static Class<?>[] paramTypesOrNull(final Class<?> type) {
-        return type == null ? null : new Class[] { type };
-    }
-
-    public static boolean allParametersOfSameType(final Class<?>[] params) {
-        final Class<?> firstParam = params[0];
-        for (int i = 1; i < params.length; i++) {
-            if (params[i] != firstParam) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-
     public static Method findAnnotatedMethod(
             final MethodFinderOptions options,
             final Object pojo,
@@ -220,47 +86,6 @@ public final class MethodFinderUtils {
         .findFirst();
     }
 
-    // -- SHORTCUTS
-
-    public static Method findMethod_returningCategory(
-            final MethodFinderOptions options,
-            final ReturnTypeCategory returnTypeCategory,
-            final Class<?> type,
-            final String name,
-            final Class<?>[] paramTypes) {
-        return findMethod_returningAnyOf(
-                options, returnTypeCategory.getReturnTypes(), type, name, paramTypes);
-    }
-
-    public static Method findMethod_returningBoolean(
-            final MethodFinderOptions options,
-            final Class<?> type,
-            final String name,
-            final Class<?>[] paramTypes) {
-        return findMethod_returningAnyOf(
-                options, ReturnTypeCategory.BOOLEAN.getReturnTypes(), type, name, paramTypes);
-    }
-
-    public static Method findMethod_returningText(
-            final MethodFinderOptions options,
-            final Class<?> type,
-            final String name,
-            final Class<?>[] paramTypes) {
-        return findMethod_returningAnyOf(
-                options, ReturnTypeCategory.TRANSLATABLE.getReturnTypes(), type, name, paramTypes);
-    }
-
-    public static Method findMethod_returningNonScalar(
-            final MethodFinderOptions options,
-            final Class<?> type,
-            final String name,
-            final Class<?> elementReturnType,
-            final Class<?>[] paramTypes) {
-
-        return findMethod_returningAnyOf(
-                options, ReturnTypeCategory.nonScalar(elementReturnType), type, name, paramTypes);
-    }
-
     // -- PPM SUPPORT
 
 
@@ -282,85 +107,41 @@ public final class MethodFinderUtils {
         }
     }
 
-    public static MethodAndPpmConstructor findMethodWithPPMArg(
+    static Stream<MethodAndPpmConstructor> findMethodWithPPMArg(
             final MethodFinderOptions options,
             final Class<?> type,
-            final String name,
             final Class<?> returnType,
             final Class<?>[] paramTypes,
             final Can<Class<?>> additionalParamTypes) {
 
-        return streamMethods(options, type, Can.ofSingleton(name), returnType)
+        return streamMethods(options, type, returnType)
             .filter(MethodUtil.Predicates.paramCount(additionalParamTypes.size()+1))
             .filter(MethodUtil.Predicates.matchParamTypes(1, additionalParamTypes))
             .map(method->MethodAndPpmCandidate.of(method, method.getParameterTypes()[0]))
             .map(ppmCandidate->ppmCandidate.lookupConstructor(paramTypes))
-            .filter(Optional::isPresent)
-            .map(Optional::get)
-            .findFirst()
-            .orElse(null);
+            .flatMap(Optional::stream);
     }
 
-    public static MethodAndPpmConstructor findMethodWithPPMArg_returningAnyOf(
+    static Stream<MethodAndPpmConstructor> findMethodWithPPMArg_returningAnyOf(
             final MethodFinderOptions options,
             final Can<Class<?>> returnTypes,
             final Class<?> type,
-            final String name,
-            final Class<?>[] paramTypes,
-            final Can<Class<?>> additionalParamTypes) {
-
-        for (val returnType : returnTypes) {
-            val result = findMethodWithPPMArg(options, type, name, returnType, paramTypes, additionalParamTypes);
-            if(result != null) {
-                return result;
-            }
-        }
-        return null;
-    }
-
-    public static MethodAndPpmConstructor findMethodWithPPMArg_returningBoolean(
-            final MethodFinderOptions options,
-            final Class<?> type,
-            final String name,
-            final Class<?>[] paramTypes,
-            final Can<Class<?>> additionalParamTypes) {
-
-        return findMethodWithPPMArg_returningAnyOf(
-                options, ReturnTypeCategory.BOOLEAN.getReturnTypes(), type, name, paramTypes, additionalParamTypes);
-    }
-
-    public static MethodAndPpmConstructor findMethodWithPPMArg_returningText(
-            final MethodFinderOptions options,
-            final Class<?> type,
-            final String name,
-            final Class<?>[] paramTypes,
-            final Can<Class<?>> additionalParamTypes) {
-
-        return findMethodWithPPMArg_returningAnyOf(
-                options, ReturnTypeCategory.TRANSLATABLE.getReturnTypes(), type, name, paramTypes, additionalParamTypes);
-    }
-
-    public static MethodAndPpmConstructor findMethodWithPPMArg_returningNonScalar(
-            final MethodFinderOptions options,
-            final Class<?> type,
-            final String name,
-            final Class<?> elementReturnType,
             final Class<?>[] paramTypes,
             final Can<Class<?>> additionalParamTypes) {
 
-        return findMethodWithPPMArg_returningAnyOf(
-                options, ReturnTypeCategory.nonScalar(elementReturnType), type, name, paramTypes, additionalParamTypes);
+        return returnTypes.stream()
+        .flatMap(returnType->findMethodWithPPMArg(options, type, returnType, paramTypes, additionalParamTypes));
     }
 
     // -- HELPER
 
-    public static Stream<Method> streamMethods(
+    private static Stream<Method> streamMethods(
             final MethodFinderOptions options,
             final Class<?> type) {
         val classCache = _ClassCache.getInstance();
-        return options.getEncapsulationPolicy().isEncapsulatedMembersSupported()
+        return (options.getEncapsulationPolicy().isEncapsulatedMembersSupported()
                 ? classCache.streamPublicOrDeclaredMethods(type)
-                : classCache.streamPublicMethods(type)
+                : classCache.streamPublicMethods(type))
                     .filter(options.getMustSatisfy()::test);
     }
 
diff --git a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/MethodFinderUtilsTest.java b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/MethodFinderUtilsTest.java
index f62fba6..b52ab9b 100644
--- a/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/MethodFinderUtilsTest.java
+++ b/core/metamodel/src/test/java/org/apache/isis/core/metamodel/facets/MethodFinderUtilsTest.java
@@ -30,8 +30,8 @@ import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
 
-import org.apache.isis.core.metamodel.methods.MethodFinderOptions;
 import org.apache.isis.core.metamodel.methods.MethodByClassMap;
+import org.apache.isis.core.metamodel.methods.MethodFinderOptions;
 import org.apache.isis.core.metamodel.methods.MethodFinderUtils;
 
 import lombok.val;
@@ -52,7 +52,7 @@ public class MethodFinderUtilsTest {
         val cache = new MethodByClassMap();
         final Method method = MethodFinderUtils
                 .findAnnotatedMethod(
-                        MethodFinderOptions.notNecessarilyPublic(),
+                        MethodFinderOptions.notNecessarilyPublic(MethodFinderOptions.ANY_NAME),
                         new WithPostConstruct(), PostConstruct.class, cache );
 
         assertThat(method, is(not(nullValue())));
@@ -68,7 +68,7 @@ public class MethodFinderUtilsTest {
         val cache = new MethodByClassMap();
         final Method method = MethodFinderUtils
                 .findAnnotatedMethod(
-                        MethodFinderOptions.notNecessarilyPublic(),
+                        MethodFinderOptions.notNecessarilyPublic(MethodFinderOptions.ANY_NAME),
                         new NoPostConstruct(), PostConstruct.class, cache);
 
         assertThat(method, is(nullValue()));
diff --git a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/mappers/FailureUtil.java b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/mappers/FailureUtil.java
index 37d66e9..af39b8a 100644
--- a/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/mappers/FailureUtil.java
+++ b/viewers/restfulobjects/viewer/src/main/java/org/apache/isis/viewer/restfulobjects/viewer/mappers/FailureUtil.java
@@ -21,8 +21,8 @@ package org.apache.isis.viewer.restfulobjects.viewer.mappers;
 import java.lang.reflect.InvocationTargetException;
 
 import org.apache.isis.commons.collections.Can;
+import org.apache.isis.core.metamodel.methods.MethodFinder;
 import org.apache.isis.core.metamodel.methods.MethodFinderOptions;
-import org.apache.isis.core.metamodel.methods.MethodFinderUtils;
 import org.apache.isis.viewer.restfulobjects.applib.RestfulResponse;
 import org.apache.isis.viewer.restfulobjects.applib.RestfulResponse.HttpStatusCode;
 
@@ -34,10 +34,12 @@ final class FailureUtil {
 
     public static HttpStatusCode getFailureStatusCodeIfAny(final Throwable ex) {
 
-        val errorCodeGetter = MethodFinderUtils.findNoArgMethod(
-                MethodFinderOptions.publicOnly(Can.ofSingleton("getErrorCode")),
-                ex.getClass(), int.class)
-                .orElse(null);
+        val errorCodeGetter = MethodFinderOptions.publicOnly(Can.ofSingleton("getErrorCode"))
+        .streamMethods(ex.getClass(), MethodFinderOptions.NO_ARG)
+        .filter(MethodFinder.hasReturnType(int.class))
+        .findFirst()
+        .orElse(null);
+
         if(errorCodeGetter!=null) {
             try {
                 val errorCode = (int)errorCodeGetter.invoke(ex);