You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@causeway.apache.org by ah...@apache.org on 2023/08/25 18:55:34 UTC

[causeway] 01/02: CAUSEWAY-3556: skip processing of methods with generic bounds

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

ahuber pushed a commit to branch 3556-generic.bound.action
in repository https://gitbox.apache.org/repos/asf/causeway.git

commit e9b5520fd43da5a51d0a7c1ff22bf008acf7b285
Author: andi-huber <ah...@apache.org>
AuthorDate: Fri Aug 25 19:45:51 2023 +0200

    CAUSEWAY-3556: skip processing of methods with generic bounds
    
    - that is, ignore entirely for action candidates
---
 .../commons/internal/reflection/_Reflect.java      | 142 ++--
 .../specloader/specimpl/FacetedMethodsBuilder.java |   6 +
 .../specimpl/dflt/ObjectSpecificationDefault.java  |  11 +
 .../DomainModelTest_usingGoodDomain.java           |  12 +-
 .../MetaModelRegressionTest.verify.approved.xml    | 827 ++++++++++++++++++++-
 ...icInterface.java => ProperGenericAbstract.java} |  10 +-
 ...ricImpl.java => ProperGenericAbstractImpl.java} |   9 +-
 .../model/good/ProperGenericInterface.java         |   4 +
 ...icImpl.java => ProperGenericInterfaceImpl.java} |   7 +-
 9 files changed, 958 insertions(+), 70 deletions(-)

diff --git a/commons/src/main/java/org/apache/causeway/commons/internal/reflection/_Reflect.java b/commons/src/main/java/org/apache/causeway/commons/internal/reflection/_Reflect.java
index 2b83a19740..283eaea928 100644
--- a/commons/src/main/java/org/apache/causeway/commons/internal/reflection/_Reflect.java
+++ b/commons/src/main/java/org/apache/causeway/commons/internal/reflection/_Reflect.java
@@ -30,6 +30,8 @@ import java.lang.reflect.Field;
 import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
 import java.util.Arrays;
 import java.util.Map;
 import java.util.Objects;
@@ -92,7 +94,7 @@ public final class _Reflect {
      * @param b
      * @see Method#equals(Object)
      */
-    public static boolean methodsSame(final Method a, final Method b) {
+    public boolean methodsSame(final Method a, final Method b) {
         if(!a.getName().equals(b.getName())) {
             return false;
         }
@@ -100,11 +102,16 @@ public final class _Reflect {
             return false;
         }
         if(!_Arrays.testAllMatch(a.getParameters(), b.getParameters(),
-                (p1, p2)->p1.getType().equals(p2.getType()))) {
+                (p1, p2)->shareSameTypeHierarchy(p1.getType(), p2.getType()))) {
+                //(p1, p2)->p1.getType().equals(p2.getType()))) {
             return false;
         }
-        return a.getReturnType().isAssignableFrom(b.getReturnType())
-                || b.getReturnType().isAssignableFrom(a.getReturnType());
+        return shareSameTypeHierarchy(a.getReturnType(), b.getReturnType());
+    }
+
+    public boolean shareSameTypeHierarchy(final @NonNull Class<?> a, final @NonNull Class<?> b) {
+        return a.isAssignableFrom(b)
+                || b.isAssignableFrom(a);
     }
 
     /**
@@ -112,7 +119,7 @@ public final class _Reflect {
      * that one which is overriding the other is returned.
      * @implNote if both declaring type and return type are the same we (arbitrarily) return b
      */
-    public static Method methodsWhichIsOverridingTheOther(final Method a, final Method b) {
+    public Method methodsWhichIsOverridingTheOther(final Method a, final Method b) {
         val aType = a.getDeclaringClass();
         val bType = b.getDeclaringClass();
         if(aType.equals(bType)) {
@@ -141,7 +148,7 @@ public final class _Reflect {
      * @param b
      * @see #methodsSame(Method, Method)
      */
-    public static int methodWeakCompare(final Method a, final Method b) {
+    public int methodWeakCompare(final Method a, final Method b) {
 
         int c = a.getName().compareTo(b.getName());
         if(c!=0) {
@@ -156,20 +163,23 @@ public final class _Reflect {
         for(int i=0; i<a.getParameterCount(); ++i) {
             c = typesCompare(paramsA[i].getType(), paramsB[i].getType());
             if(c!=0) {
-                return c;
+                if(shareSameTypeHierarchy(paramsA[i].getType(), paramsB[i].getType())) {
+                    // continue
+                } else {
+                    return c;
+                }
             }
         }
         c = typesCompare(a.getReturnType(), b.getReturnType());
         if(c!=0) {
-            return a.getReturnType().isAssignableFrom(b.getReturnType())
-                    || b.getReturnType().isAssignableFrom(a.getReturnType())
+            return shareSameTypeHierarchy(a.getReturnType(), b.getReturnType())
                     ? 0 // same
                     : c;
         }
         return 0; // equal
     }
 
-    public static int typesCompare(final Class<?> a, final Class<?> b) {
+    public int typesCompare(final Class<?> a, final Class<?> b) {
         return a.getName().compareTo(b.getName());
     }
 
@@ -178,7 +188,7 @@ public final class _Reflect {
      * (method, field or constructor)
      * @param obj
      */
-    public static boolean canAccess(
+    public boolean canAccess(
             final @Nullable AccessibleObject member,
             final @Nullable Object obj) {
         return member != null
@@ -189,7 +199,7 @@ public final class _Reflect {
      * Returns whether a {@link Member} is public and not synthetic (can be accessed).
      * @param member Member to check
      */
-    public static boolean isPublicNonSynthetic(final @Nullable Member member) {
+    public boolean isPublicNonSynthetic(final @Nullable Member member) {
         return member != null
                 && Modifier.isPublic(member.getModifiers())
                 && !member.isSynthetic();
@@ -199,7 +209,7 @@ public final class _Reflect {
      * Whether member name equals given {@code memberName}
      * @param memberName
      */
-    public static <T extends Member> Predicate<T> withName(final @NonNull String memberName) {
+    public <T extends Member> Predicate<T> withName(final @NonNull String memberName) {
         return m -> m != null && memberName.equals(m.getName());
     }
 
@@ -207,7 +217,7 @@ public final class _Reflect {
      * Whether member name starts with given {@code prefix}
      * @param prefix
      */
-    public static <T extends Member> Predicate<T> withPrefix(final @NonNull String prefix) {
+    public <T extends Member> Predicate<T> withPrefix(final @NonNull String prefix) {
         return m -> m != null && m.getName().startsWith(prefix);
     }
 
@@ -215,7 +225,7 @@ public final class _Reflect {
      * Whether method parameters count equal to given {@code count}
      * @param count
      */
-    public static Predicate<Method> withMethodParametersCount(final int count) {
+    public Predicate<Method> withMethodParametersCount(final int count) {
         return (final Method m) -> m != null && m.getParameterTypes().length == count;
     }
 
@@ -223,7 +233,7 @@ public final class _Reflect {
      * Whether field type is assignable to given {@code type}
      * @param type
      */
-    public static <T> Predicate<Field> withTypeAssignableTo(final @NonNull Class<T> type) {
+    public <T> Predicate<Field> withTypeAssignableTo(final @NonNull Class<T> type) {
         return (final Field f) -> f != null && type.isAssignableFrom(f.getType());
     }
 
@@ -234,7 +244,7 @@ public final class _Reflect {
      * @param type (nullable)
      * @param ignoreAccess - whether to include non-public members
      */
-    public static Stream<Field> streamFields(
+    public Stream<Field> streamFields(
             final @Nullable Class<?> type,
             final boolean ignoreAccess) {
 
@@ -252,7 +262,7 @@ public final class _Reflect {
      * @param type (nullable)
      * @param ignoreAccess - whether to include non-public members
      */
-    public static Stream<Field> streamAllFields(
+    public Stream<Field> streamAllFields(
             final @Nullable Class<?> type,
             final boolean ignoreAccess) {
 
@@ -268,7 +278,7 @@ public final class _Reflect {
      * @param ignoreAccess - whether to include non-public members
      * @return non-null
      */
-    public static Stream<Method> streamMethods(
+    public Stream<Method> streamMethods(
             final @Nullable Class<?> type,
             final boolean ignoreAccess) {
 
@@ -282,7 +292,7 @@ public final class _Reflect {
         return _NullSafe.stream(type.getMethods());
     }
 
-    public static Stream<Method> streamInheritedMethods(final Method method) {
+    public Stream<Method> streamInheritedMethods(final Method method) {
         return streamAllMethods(method.getDeclaringClass(), true)
                 .filter(candidateMethod->methodsSame(candidateMethod, method));
     }
@@ -293,7 +303,7 @@ public final class _Reflect {
      * @param ignoreAccess - whether to include non-public members
      * @return non-null
      */
-    public static Stream<Method> streamAllMethods(
+    public Stream<Method> streamAllMethods(
             final @Nullable Class<?> type,
             final boolean ignoreAccess) {
 
@@ -326,7 +336,7 @@ public final class _Reflect {
      * @param interfacePolicy - whether to include all interfaces implemented by given {@code type} at the end
      * @return non-null
      */
-    public static Stream<Class<?>> streamTypeHierarchy(
+    public Stream<Class<?>> streamTypeHierarchy(
             final @Nullable Class<?> type,
             final @NonNull InterfacePolicy interfacePolicy) {
 
@@ -348,7 +358,7 @@ public final class _Reflect {
      * @return the first matching annotation, or {@code null} if not found
      * @throws NullPointerException - if annotationClass is {@code null}
      */
-    public static <T extends Annotation> T getAnnotation(
+    public <T extends Annotation> T getAnnotation(
             final Class<?> cls,
             final Class<T> annotationClass) {
 
@@ -406,7 +416,7 @@ public final class _Reflect {
      * @throws NullPointerException
      *            if the method or annotation are {@code null}
      */
-    public static <A extends Annotation> A getAnnotation(
+    public <A extends Annotation> A getAnnotation(
             final @NonNull Method method,
             final @NonNull Class<A> annotationCls,
             final boolean searchSupers,
@@ -447,7 +457,7 @@ public final class _Reflect {
      * @param annotationName - fully qualified class name of the {@link Annotation} to match against
      * @return false - if any of the arguments is null
      */
-    public static boolean containsAnnotation(final @Nullable Class<?> cls, final @Nullable String annotationName) {
+    public boolean containsAnnotation(final @Nullable Class<?> cls, final @Nullable String annotationName) {
         if(cls==null || _Strings.isEmpty(annotationName)) {
             return false;
         }
@@ -462,20 +472,20 @@ public final class _Reflect {
     // -- FIND GETTER
 
     @SneakyThrows
-    public static Stream<PropertyDescriptor> streamGetters(final @NonNull Class<?> cls) {
+    public Stream<PropertyDescriptor> streamGetters(final @NonNull Class<?> cls) {
         return Stream.of(
                 Introspector.getBeanInfo(cls, Object.class)
                     .getPropertyDescriptors())
                 .filter(pd->pd.getReadMethod()!=null);
     }
 
-    public static Map<String, Method> getGettersByName(final @NonNull Class<?> cls) {
+    public Map<String, Method> getGettersByName(final @NonNull Class<?> cls) {
         return streamGetters(cls)
                 .collect(Collectors.toMap(PropertyDescriptor::getName, PropertyDescriptor::getReadMethod));
     }
 
 
-    public static Method getGetter(final Class<?> cls, final String propertyName) throws IntrospectionException {
+    public Method getGetter(final Class<?> cls, final String propertyName) throws IntrospectionException {
         final BeanInfo beanInfo = Introspector.getBeanInfo(cls);
         for(PropertyDescriptor pd:beanInfo.getPropertyDescriptors()){
             if(!pd.getName().equals(propertyName))
@@ -486,7 +496,7 @@ public final class _Reflect {
     }
 
     @SneakyThrows
-    public static Object readFromGetterOn(
+    public Object readFromGetterOn(
             final @NonNull Method getter,
             final @NonNull Object target) {
         return getter.invoke(target);
@@ -494,7 +504,7 @@ public final class _Reflect {
 
     // -- FIND SETTER
 
-    public static Method getSetter(final Class<?> cls, final String propertyName) throws IntrospectionException {
+    public Method getSetter(final Class<?> cls, final String propertyName) throws IntrospectionException {
         final BeanInfo beanInfo = Introspector.getBeanInfo(cls);
         for(PropertyDescriptor pd:beanInfo.getPropertyDescriptors()){
             if(!pd.getName().equals(propertyName))
@@ -505,7 +515,7 @@ public final class _Reflect {
     }
 
     @SneakyThrows
-    public static void writeToSetterOn(
+    public void writeToSetterOn(
             final @NonNull Method setter,
             final @NonNull Object target,
             final @NonNull Object value) {
@@ -515,7 +525,7 @@ public final class _Reflect {
 
     // -- MODIFIERS
 
-    public static Object getFieldOn(
+    public Object getFieldOn(
             final @NonNull Field field,
             final @NonNull Object target) throws IllegalArgumentException, IllegalAccessException {
 
@@ -532,7 +542,7 @@ public final class _Reflect {
         /*sonar-ignore-off*/
     }
 
-    public static void setFieldOn(
+    public void setFieldOn(
             final @NonNull Field field,
             final @NonNull Object target,
             final Object fieldValue) throws IllegalArgumentException, IllegalAccessException {
@@ -552,7 +562,7 @@ public final class _Reflect {
     }
 
 
-    public static Try<Object> invokeMethodOn(
+    public Try<Object> invokeMethodOn(
             final @NonNull Method method,
             final @NonNull Object target,
             final Object... args) {
@@ -572,7 +582,7 @@ public final class _Reflect {
         /*sonar-ignore-off*/
     }
 
-    public static <T> Try<T> invokeConstructor(
+    public <T> Try<T> invokeConstructor(
             final @NonNull Constructor<T> constructor,
             final Object... args) {
 
@@ -594,18 +604,18 @@ public final class _Reflect {
 
     // -- COMMON CONSTRUCTOR IDIOMS
 
-    public static Can<Constructor<?>> getDeclaredConstructors(final Class<?> cls) {
+    public Can<Constructor<?>> getDeclaredConstructors(final Class<?> cls) {
         return Can.ofArray(cls.getDeclaredConstructors());
     }
 
-    public static Can<Constructor<?>> getPublicConstructors(final Class<?> cls) {
+    public Can<Constructor<?>> getPublicConstructors(final Class<?> cls) {
         return Can.ofArray(cls.getConstructors());
     }
 
     // -- GENENERIC TYPE ARG INTROSPECTION
 
     @lombok.Value(staticConstructor = "of")
-    public static class MethodAndImplementingClass {
+    public class MethodAndImplementingClass {
         final @NonNull Method method;
         final @NonNull Class<?> implementingClass;
         /**
@@ -641,7 +651,7 @@ public final class _Reflect {
     }
 
     @lombok.Value(staticConstructor = "of")
-    public static class ConstructorAndImplementingClass {
+    public class ConstructorAndImplementingClass {
         final @NonNull Constructor<?> constructor;
         final @NonNull Class<?> implementingClass;
         /**
@@ -679,9 +689,9 @@ public final class _Reflect {
     // -- FILTER
 
     @UtilityClass
-    public static class Filter {
+    public class Filter {
 
-        public static Predicate<Method> isGetter() {
+        public Predicate<Method> isGetter() {
             return method->method!=null
                     && method.getParameterCount()==0
                     && method.getReturnType()!=void.class
@@ -690,29 +700,29 @@ public final class _Reflect {
                                 && method.getReturnType()==boolean.class));
         }
 
-        public static Predicate<Method> hasReturnType(final Class<?> expectedReturnType) {
+        public Predicate<Method> hasReturnType(final Class<?> expectedReturnType) {
             return method->expectedReturnType.isAssignableFrom(method.getReturnType());
         }
 
-        public static Predicate<Method> hasReturnTypeAnyOf(final Can<Class<?>> allowedReturnTypes) {
+        public Predicate<Method> hasReturnTypeAnyOf(final Can<Class<?>> allowedReturnTypes) {
             return method->allowedReturnTypes.stream()
                     .anyMatch(allowedReturnType->allowedReturnType.isAssignableFrom(method.getReturnType()));
         }
 
-        public static Predicate<Executable> isPublic() {
+        public Predicate<Executable> isPublic() {
             return ex->Modifier.isPublic(ex.getModifiers());
         }
 
-        public static Predicate<Executable> paramCount(final int paramCount) {
+        public Predicate<Executable> paramCount(final int paramCount) {
             return ex->ex.getParameterCount() == paramCount;
         }
 
-        public static Predicate<Executable> paramAssignableFrom(final int paramIndex, final Class<?> paramType) {
+        public Predicate<Executable> paramAssignableFrom(final int paramIndex, final Class<?> paramType) {
             return ex->ex.getParameterTypes()[paramIndex].isAssignableFrom(paramType);
         }
 
         //TODO simple array compare should do
-        public static Predicate<Executable> paramSignatureMatch(final Class<?>[] matchingParamTypes) {
+        public Predicate<Executable> paramSignatureMatch(final Class<?>[] matchingParamTypes) {
             return ex->{
                 // check params (if required)
                 if (matchingParamTypes != null) {
@@ -731,7 +741,7 @@ public final class _Reflect {
             };
         }
 
-        public static Predicate<Executable> paramAssignableFromValue(final int paramIndex, final @Nullable Object value) {
+        public Predicate<Executable> paramAssignableFromValue(final int paramIndex, final @Nullable Object value) {
             if(value==null) {
                 return _Predicates.alwaysTrue();
             }
@@ -743,7 +753,7 @@ public final class _Reflect {
     /**
      * Lookup regular method for a synthetic one in the method's declaring class type-hierarchy.
      */
-    public static Optional<Method> lookupRegularMethodForSynthetic(final @NonNull Method syntheticMethod) {
+    public Optional<Method> lookupRegularMethodForSynthetic(final @NonNull Method syntheticMethod) {
 
         if(!syntheticMethod.isSynthetic()) {
             return Optional.of(syntheticMethod);
@@ -756,7 +766,7 @@ public final class _Reflect {
         .findFirst();
     }
 
-    private static Predicate<Method> methodMatcherOnNameAndSignature(final @NonNull Method ref) {
+    private Predicate<Method> methodMatcherOnNameAndSignature(final @NonNull Method ref) {
         val refSignature = ref.getParameterTypes();
         return other->
             (!ref.getName().equals(other.getName()))
@@ -764,7 +774,7 @@ public final class _Reflect {
             : Arrays.equals(refSignature, other.getParameterTypes());
     }
 
-    public static String methodToShortString(final @NonNull Method method) {
+    public String methodToShortString(final @NonNull Method method) {
 
         return method.getName() + "(" +
 
@@ -778,8 +788,36 @@ public final class _Reflect {
     /**
      * Determine if the supplied method is declared within a non-static <em>inner class</em>.
      */
-    public static boolean isNonStaticInnerMethod(final @NonNull Method method) {
+    public boolean isNonStaticInnerMethod(final @NonNull Method method) {
         return ClassUtils.isInnerClass(method.getDeclaringClass());
     }
 
+    /**
+     * Whether has any generic bounds on any return type or parameter type(s).
+     */
+    public boolean hasGenericBounds(final @NonNull Method method) {
+        return hasGenericReturn(method)
+                || hasGenericParam(method);
+    }
+
+    /**
+     * Whether has any generic bounds on the method return type.
+     */
+    public boolean hasGenericReturn(final @NonNull Method method) {
+        return method.getGenericReturnType() instanceof TypeVariable<?>;
+    }
+
+    /**
+     * Whether has any generic bounds any parameter type(s).
+     */
+    public boolean hasGenericParam(final @NonNull Method method) {
+        final Type[] genericParameterTypes = method.getGenericParameterTypes();
+        for(int i=0; i<method.getParameterCount(); ++i) {
+            if(genericParameterTypes[i] instanceof TypeVariable<?>) {
+                return true;
+            }
+        }
+        return false;
+    }
+
 }
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java
index 3205167191..1dcd06e0db 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/FacetedMethodsBuilder.java
@@ -422,6 +422,12 @@ implements HasMetaModelContext {
             return false;
         }
 
+        //[CAUSEWAY-3556] skip processing of methods with bounded return or any bounded param
+        // that is, ignore entirely
+        if(_Reflect.hasGenericBounds(actionMethod)) {
+            return false;
+        }
+
         val hasActionAnnotation = _Annotations
                 .isPresent(actionMethod, Action.class);
 
diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
index d8866d7cd4..9d5248bcfc 100644
--- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
+++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/specimpl/dflt/ObjectSpecificationDefault.java
@@ -222,7 +222,18 @@ implements FacetHolder {
     }
 
     private ObjectAction createAction(final FacetedMethod facetedMethod) {
+
         if (facetedMethod.getFeatureType().isAction()) {
+
+            //TODO[CAUSEWAY-3556] perhaps let _ClassCache handle this
+            final boolean hasGenericBounds = facetedMethod.getMethod().asMethod()
+                    .map(method->_Reflect.hasGenericBounds(method))
+                    .orElse(false);
+
+            if(hasGenericBounds) {
+                return null;
+            }
+
             /* Assuming, that facetedMethod was already populated with ContributingFacet,
              * we copy the mixin-sort information from the FacetedMethod to the MixinFacet
              * that is held by the mixin's type spec. */
diff --git a/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java b/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java
index d1644e8003..2bbc869cd5 100644
--- a/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java
+++ b/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/DomainModelTest_usingGoodDomain.java
@@ -80,7 +80,8 @@ import org.apache.causeway.testdomain.model.good.ProperChoicesWhenActionHasParam
 import org.apache.causeway.testdomain.model.good.ProperChoicesWhenChoicesFrom;
 import org.apache.causeway.testdomain.model.good.ProperElementTypeVm;
 import org.apache.causeway.testdomain.model.good.ProperFullyImpl;
-import org.apache.causeway.testdomain.model.good.ProperGenericImpl;
+import org.apache.causeway.testdomain.model.good.ProperGenericAbstractImpl;
+import org.apache.causeway.testdomain.model.good.ProperGenericInterfaceImpl;
 import org.apache.causeway.testdomain.model.good.ProperInterface2;
 import org.apache.causeway.testdomain.model.good.ProperMemberInheritanceInterface;
 import org.apache.causeway.testdomain.model.good.ProperMemberInheritance_usingAbstract;
@@ -243,7 +244,14 @@ class DomainModelTest_usingGoodDomain {
 
     @Test
     void genericInterface_whenImplemented_shouldBeSupported() {
-        val tester = testerFactory.propertyTester(ProperGenericImpl.class, "value");
+        val tester = testerFactory.propertyTester(ProperGenericInterfaceImpl.class, "value");
+        tester.assertExists(true);
+        tester.assertValue("aValue");
+    }
+
+    @Test
+    void genericAbstract_whenImplemented_shouldBeSupported() {
+        val tester = testerFactory.propertyTester(ProperGenericAbstractImpl.class, "value");
         tester.assertExists(true);
         tester.assertValue("aValue");
     }
diff --git a/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/MetaModelRegressionTest.verify.approved.xml b/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/MetaModelRegressionTest.verify.approved.xml
index 8a71daabe4..e1a457515e 100644
--- a/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/MetaModelRegressionTest.verify.approved.xml
+++ b/regressiontests/stable-domainmodel/src/test/java/org/apache/causeway/testdomain/domainmodel/MetaModelRegressionTest.verify.approved.xml
@@ -7266,22 +7266,22 @@
             </mml:act>
         </mml:actions>
     </mml:domainClassDto>
-    <mml:domainClassDto id="org.apache.causeway.testdomain.model.good.ProperGenericImpl">
+    <mml:domainClassDto id="org.apache.causeway.testdomain.model.good.ProperGenericAbstractImpl">
         <mml:facets>
             <mml:facet id="org.apache.causeway.core.metamodel.facets.all.named.MemberNamedFacet" fqcn="org.apache.causeway.core.metamodel.facets.all.named.MemberNamedFacetForStaticMemberName">
-                <mml:attr name="context" value="TranslationContext(name=org.apache.causeway.testdomain.model.good.ProperGenericImpl#)"/>
+                <mml:attr name="context" value="TranslationContext(name=org.apache.causeway.testdomain.model.good.ProperGenericAbstractImpl#)"/>
                 <mml:attr name="facet" value="MemberNamedFacetForStaticMemberName"/>
-                <mml:attr name="originalText" value="Proper Generic Impl"/>
+                <mml:attr name="originalText" value="Proper Generic Abstract Impl"/>
                 <mml:attr name="precedence" value="DEFAULT"/>
-                <mml:attr name="translated" value="Proper Generic Impl"/>
+                <mml:attr name="translated" value="Proper Generic Abstract Impl"/>
             </mml:facet>
             <mml:facet id="org.apache.causeway.core.metamodel.facets.all.named.ObjectNamedFacet" fqcn="org.apache.causeway.core.metamodel.facets.all.named.ObjectNamedFacetSynthesized">
-                <mml:attr name="context" value="TranslationContext(name=org.apache.causeway.testdomain.model.good.ProperGenericImpl#)"/>
+                <mml:attr name="context" value="TranslationContext(name=org.apache.causeway.testdomain.model.good.ProperGenericAbstractImpl#)"/>
                 <mml:attr name="facet" value="ObjectNamedFacetSynthesized"/>
                 <mml:attr name="hasNoun" value="true"/>
-                <mml:attr name="originalText" value="Optional[Proper Generic Impl]"/>
+                <mml:attr name="originalText" value="Optional[Proper Generic Abstract Impl]"/>
                 <mml:attr name="precedence" value="SYNTHESIZED"/>
-                <mml:attr name="translated" value="Optional[Proper Generic Impl]"/>
+                <mml:attr name="translated" value="Optional[Proper Generic Abstract Impl]"/>
             </mml:facet>
             <mml:facet id="org.apache.causeway.core.metamodel.facets.object.callbacks.CreatedLifecycleEventFacet" fqcn="org.apache.causeway.core.metamodel.facets.object.callbacks.CreatedLifecycleEventFacetForDomainObjectAnnotation">
                 <mml:attr name="facet" value="CreatedLifecycleEventFacetForDomainObjectAnnotation"/>
@@ -7376,10 +7376,10 @@
                         <mml:attr name="typicalLengthFacet" value="org.apache.causeway.core.metamodel.facets.object.value.TypicalLengthFacetFromValueFacet"/>
                     </mml:facet>
                     <mml:facet id="org.apache.causeway.core.metamodel.facets.propcoll.accessor.PropertyOrCollectionAccessorFacet" fqcn="org.apache.causeway.core.metamodel.facets.properties.accessor.PropertyAccessorFacetViaAccessor">
-                        <mml:attr name="declaringType" value="org.apache.causeway.testdomain.model.good.ProperGenericImpl"/>
+                        <mml:attr name="declaringType" value="org.apache.causeway.testdomain.model.good.ProperGenericAbstractImpl"/>
                         <mml:attr name="facet" value="PropertyAccessorFacetViaAccessor"/>
                         <mml:attr name="intent.getValue" value="ACCESSOR"/>
-                        <mml:attr name="methods" value="public java.lang.String org.apache.causeway.testdomain.model.good.ProperGenericImpl.getValue()"/>
+                        <mml:attr name="methods" value="public java.lang.String org.apache.causeway.testdomain.model.good.ProperGenericAbstractImpl.getValue()"/>
                         <mml:attr name="precedence" value="DEFAULT"/>
                     </mml:facet>
                     <mml:facet id="org.apache.causeway.core.metamodel.facets.properties.property.modify.PropertyDomainEventFacet" fqcn="org.apache.causeway.core.metamodel.facets.properties.property.modify.PropertyDomainEventFacet">
@@ -7403,7 +7403,814 @@
                     <mml:facet id="org.apache.causeway.core.metamodel.facets.properties.update.init.PropertyInitializationFacet" fqcn="org.apache.causeway.core.metamodel.facets.properties.update.init.PropertyInitializationFacetViaSetterMethod">
                         <mml:attr name="facet" value="PropertyInitializationFacetViaSetterMethod"/>
                         <mml:attr name="intent.setValue" value="MODIFY_PROPERTY"/>
-                        <mml:attr name="methods" value="public void org.apache.causeway.testdomain.model.good.ProperGenericImpl.setValue(java.lang.String)"/>
+                        <mml:attr name="methods" value="public void org.apache.causeway.testdomain.model.good.ProperGenericAbstractImpl.setValue(java.lang.String)"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.properties.update.modify.PropertySetterFacet" fqcn="org.apache.causeway.core.metamodel.facets.properties.property.modify.PropertyModifyFacetForSetting">
+                        <mml:attr name="eventType" value="org.apache.causeway.applib.events.domain.PropertyDomainEvent.Default"/>
+                        <mml:attr name="eventTypeOrigin" value="DEFAULT"/>
+                        <mml:attr name="facet" value="PropertyModifyFacetForSetting"/>
+                        <mml:attr name="getterFacet" value="org.apache.causeway.core.metamodel.facets.properties.accessor.PropertyAccessorFacetViaAccessor"/>
+                        <mml:attr name="isPostable" value="true"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="setterFacet" value="org.apache.causeway.core.metamodel.facets.properties.update.modify.PropertySetterFacetViaSetterMethod"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.properties.validating.PropertyValidateFacet" fqcn="org.apache.causeway.core.metamodel.facets.properties.validating.dflt.PropertyValidateFacetDefault">
+                        <mml:attr name="facet" value="PropertyValidateFacetDefault"/>
+                        <mml:attr name="interactionAdvisors" value="Validating"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.postprocessors.allbutparam.authorization.AuthorizationFacet" fqcn="org.apache.causeway.core.metamodel.postprocessors.allbutparam.authorization.AuthorizationFacetImpl">
+                        <mml:attr name="facet" value="AuthorizationFacetImpl"/>
+                        <mml:attr name="interactionAdvisors" value="HidingOrShowing, DisablingOrEnabling"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                </mml:facets>
+                <mml:type>java.lang.String</mml:type>
+            </mml:prop>
+        </mml:properties>
+        <mml:collections/>
+        <mml:actions>
+            <mml:act id="downloadLayout" mixedIn="true">
+                <mml:facets>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.action.explicit.ActionExplicitFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.explicit.ActionExplicitFacetForActionAnnotation">
+                        <mml:attr name="facet" value="ActionExplicitFacetForActionAnnotation"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionDomainEventFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionDomainEventFacet">
+                        <mml:attr name="eventType" value="org.apache.causeway.applib.mixins.layout.Object_downloadLayout.ActionDomainEvent"/>
+                        <mml:attr name="eventTypeOrigin" value="ANNOTATED_MEMBER"/>
+                        <mml:attr name="facet" value="ActionDomainEventFacet"/>
+                        <mml:attr name="interactionAdvisors" value="Validating, HidingOrShowing, DisablingOrEnabling"/>
+                        <mml:attr name="isPostable" value="true"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionInvocationFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionInvocationFacetForAction">
+                        <mml:attr name="declaringType" value="org.apache.causeway.applib.mixins.layout.Object_downloadLayout"/>
+                        <mml:attr name="eventType" value="org.apache.causeway.applib.mixins.layout.Object_downloadLayout.ActionDomainEvent"/>
+                        <mml:attr name="eventTypeOrigin" value="ANNOTATED_MEMBER"/>
+                        <mml:attr name="facet" value="ActionInvocationFacetForAction"/>
+                        <mml:attr name="intent.act" value="EXECUTE"/>
+                        <mml:attr name="isPostable" value="true"/>
+                        <mml:attr name="methods" value="public java.lang.Object org.apache.causeway.applib.mixins.layout.Object_downloadLayout.act(java.lang.String,org.apache.causeway.applib.services.layout.LayoutExportStyle,org.apache.causeway.applib.value.NamedWithMimeType$CommonMimeType)"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="returnType" value="java.lang.Object"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.contributing.ContributingFacet">
+                        <mml:attr name="contributing" value="AS_ACTION"/>
+                        <mml:attr name="facet" value="ContributingFacetAbstract.1"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.position.ActionPositionFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.layout.ActionPositionFacetForActionLayoutAnnotation">
+                        <mml:attr name="facet" value="ActionPositionFacetForActionLayoutAnnotation"/>
+                        <mml:attr name="position" value="PANEL_DROPDOWN"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.prototype.PrototypeFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.prototype.PrototypeFacetForActionAnnotation">
+                        <mml:attr name="deploymentType" value="PRODUCTION"/>
+                        <mml:attr name="facet" value="PrototypeFacetForActionAnnotation"/>
+                        <mml:attr name="interactionAdvisors" value="HidingOrShowing"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.redirect.RedirectFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.layout.RedirectFacetFromActionLayoutAnnotation">
+                        <mml:attr name="facet" value="RedirectFacetFromActionLayoutAnnotation"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="redirect" value="AS_CONFIGURED"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.semantics.ActionSemanticsFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.semantics.ActionSemanticsFacetForActionAnnotation">
+                        <mml:attr name="facet" value="ActionSemanticsFacetForActionAnnotation"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="value" value="SAFE"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.all.described.MemberDescribedFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.layout.MemberDescribedFacetForActionLayoutAnnotation">
+                        <mml:attr name="context" value="TranslationContext(name=org.apache.causeway.applib.mixins.layout.Object_downloadLayout#act())"/>
+                        <mml:attr name="facet" value="MemberDescribedFacetForActionLayoutAnnotation"/>
+                        <mml:attr name="originalText" value="Downloads the Xxx.layout... layout file effective/inferred for this object"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="translated" value="Downloads the Xxx.layout... layout file effective/inferred for this object"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.all.named.MemberNamedFacet" fqcn="org.apache.causeway.core.metamodel.facets.all.named.MemberNamedFacetForStaticMemberName">
+                        <mml:attr name="context" value="TranslationContext(name=org.apache.causeway.applib.mixins.layout.Object_downloadLayout#act())"/>
+                        <mml:attr name="facet" value="MemberNamedFacetForStaticMemberName"/>
+                        <mml:attr name="originalText" value="Download Layout"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="translated" value="Download Layout"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.collections.collection.defaultview.DefaultViewFacet" fqcn="org.apache.causeway.core.metamodel.facets.collections.layout.DefaultViewFacetAsConfigured">
+                        <mml:attr name="facet" value="DefaultViewFacetAsConfigured"/>
+                        <mml:attr name="precedence" value="LOW"/>
+                        <mml:attr name="value" value="table"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.members.cssclassfa.CssClassFaFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.layout.CssClassFaFacetForActionLayoutAnnotation">
+                        <mml:attr name="classes" value="fa fa-fw fa-download"/>
+                        <mml:attr name="facet" value="CssClassFaFacetForActionLayoutAnnotation"/>
+                        <mml:attr name="position" value="LEFT"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.members.layout.group.LayoutGroupFacet" fqcn="org.apache.causeway.core.metamodel.facets.members.layout.group.LayoutGroupFacetFromActionLayoutAnnotation">
+                        <mml:attr name="facet" value="LayoutGroupFacetFromActionLayoutAnnotation"/>
+                        <mml:attr name="groupId" value="metadata"/>
+                        <mml:attr name="groupName" value="Metadata"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.members.layout.order.LayoutOrderFacet" fqcn="org.apache.causeway.core.metamodel.facets.members.layout.order.LayoutOrderFacetFromActionLayoutAnnotation">
+                        <mml:attr name="facet" value="LayoutOrderFacetFromActionLayoutAnnotation"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="sequence" value="700.1"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.object.promptStyle.PromptStyleFacet" fqcn="org.apache.causeway.core.metamodel.facets.object.promptStyle.PromptStyleFacetAsConfigured">
+                        <mml:attr name="facet" value="PromptStyleFacetAsConfigured"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="promptStyle" value="INLINE"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.object.tabledec.TableDecoratorFacet" fqcn="org.apache.causeway.core.metamodel.facets.collections.layout.tabledec.TableDecoratorFacetFromConfiguration">
+                        <mml:attr name="facet" value="TableDecoratorFacetFromConfiguration"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="value" value="org.apache.causeway.applib.annotation.TableDecorator.Default"/>
+                    </mml:facet>
+                </mml:facets>
+                <mml:returnType>java.lang.Object</mml:returnType>
+                <mml:params>
+                    <mml:param id="fileName" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="mml:scalarParam">
+                        <mml:facets>
+                            <mml:facet id="org.apache.causeway.core.metamodel.facets.all.described.ParamDescribedFacet" fqcn="org.apache.causeway.core.metamodel.facets.param.layout.ParamDescribedFacetForParameterLayoutAnnotation">
+<mml:attr name="context" value="TranslationContext(name=org.apache.causeway.applib.mixins.layout.Object_downloadLayout#act())"/>
+<mml:attr name="facet" value="ParamDescribedFacetForParameterLayoutAnnotation"/>
+<mml:attr name="originalText" value="File name extension can be omitted."/>
+<mml:attr name="precedence" value="DEFAULT"/>
+<mml:attr name="translated" value="File name extension can be omitted."/>
+                            </mml:facet>
+                            <mml:facet id="org.apache.causeway.core.metamodel.facets.all.named.ParamNamedFacet" fqcn="org.apache.causeway.core.metamodel.facets.param.layout.NamedFacetForParameterLayoutAnnotation">
+<mml:attr name="context" value="TranslationContext(name=org.apache.causeway.applib.mixins.layout.Object_downloadLayout#act())"/>
+<mml:attr name="facet" value="NamedFacetForParameterLayoutAnnotation"/>
+<mml:attr name="originalText" value="File name"/>
+<mml:attr name="precedence" value="DEFAULT"/>
+<mml:attr name="translated" value="File name"/>
+                            </mml:facet>
+                            <mml:facet id="org.apache.causeway.core.metamodel.facets.objectvalue.labelat.LabelAtFacet" fqcn="org.apache.causeway.core.metamodel.facets.fallback.LabelAtFacetFromLayoutConfiguration">
+<mml:attr name="facet" value="LabelAtFacetFromLayoutConfiguration"/>
+<mml:attr name="labelPosition" value="NOT_SPECIFIED"/>
+<mml:attr name="precedence" value="LOW"/>
+                            </mml:facet>
+                            <mml:facet id="org.apache.causeway.core.metamodel.facets.param.defaults.ActionParameterDefaultsFacet" fqcn="org.apache.causeway.core.metamodel.facets.param.defaults.methodnum.ActionParameterDefaultsFacetViaMethod">
+<mml:attr name="facet" value="ActionParameterDefaultsFacetViaMethod"/>
+<mml:attr name="intent.default0Act" value="DEFAULTS"/>
+<mml:attr name="methods" value="public java.lang.String org.apache.causeway.applib.mixins.layout.Object_downloadLayout.default0Act()"/>
+<mml:attr name="precedence" value="DEFAULT"/>
+                            </mml:facet>
+                            <mml:facet id="org.apache.causeway.core.metamodel.facets.param.parameter.depdef.ParameterDependentDefaultsFacet" fqcn="org.apache.causeway.core.metamodel.facets.param.parameter.depdef.ParameterDependentDefaultsFacetFromConfiguration">
+<mml:attr name="facet" value="ParameterDependentDefaultsFacetFromConfiguration"/>
+<mml:attr name="precedence" value="DEFAULT"/>
+<mml:attr name="value" value="UPDATE_DEPENDENT"/>
+                            </mml:facet>
+                        </mml:facets>
+                        <mml:type>java.lang.String</mml:type>
+                    </mml:param>
+                    <mml:param id="style" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="mml:scalarParam">
+                        <mml:facets>
+                            <mml:facet id="org.apache.causeway.core.metamodel.facets.all.named.ParamNamedFacet" fqcn="org.apache.causeway.core.metamodel.facets.param.name.NamedFacetForParameterUsingReflection">
+<mml:attr name="context" value="TranslationContext(name=org.apache.causeway.applib.mixins.layout.Object_downloadLayout#act())"/>
+<mml:attr name="facet" value="NamedFacetForParameterUsingReflection"/>
+<mml:attr name="originalText" value="Style"/>
+<mml:attr name="precedence" value="LOW"/>
+<mml:attr name="translated" value="Style"/>
+                            </mml:facet>
+                            <mml:facet id="org.apache.causeway.core.metamodel.facets.objectvalue.labelat.LabelAtFacet" fqcn="org.apache.causeway.core.metamodel.facets.fallback.LabelAtFacetFromLayoutConfiguration">
+<mml:attr name="facet" value="LabelAtFacetFromLayoutConfiguration"/>
+<mml:attr name="labelPosition" value="NOT_SPECIFIED"/>
+<mml:attr name="precedence" value="LOW"/>
+                            </mml:facet>
+                            <mml:facet id="org.apache.causeway.core.metamodel.facets.param.defaults.ActionParameterDefaultsFacet" fqcn="org.apache.causeway.core.metamodel.facets.param.defaults.methodnum.ActionParameterDefaultsFacetViaMethod">
+<mml:attr name="facet" value="ActionParameterDefaultsFacetViaMethod"/>
+<mml:attr name="intent.default1Act" value="DEFAULTS"/>
+<mml:attr name="methods" value="public org.apache.causeway.applib.services.layout.LayoutExportStyle org.apache.causeway.applib.mixins.layout.Object_downloadLayout.default1Act()"/>
+<mml:attr name="precedence" value="DEFAULT"/>
+                            </mml:facet>
+                            <mml:facet id="org.apache.causeway.core.metamodel.facets.param.parameter.depdef.ParameterDependentDefaultsFacet" fqcn="org.apache.causeway.core.metamodel.facets.param.parameter.depdef.ParameterDependentDefaultsFacetFromConfiguration">
+<mml:attr name="facet" value="ParameterDependentDefaultsFacetFromConfiguration"/>
+<mml:attr name="precedence" value="DEFAULT"/>
+<mml:attr name="value" value="UPDATE_DEPENDENT"/>
+                            </mml:facet>
+                        </mml:facets>
+                        <mml:type>org.apache.causeway.applib.services.layout.LayoutExportStyle</mml:type>
+                    </mml:param>
+                    <mml:param id="format" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="mml:scalarParam">
+                        <mml:facets>
+                            <mml:facet id="org.apache.causeway.core.metamodel.facets.all.named.ParamNamedFacet" fqcn="org.apache.causeway.core.metamodel.facets.param.name.NamedFacetForParameterUsingReflection">
+<mml:attr name="context" value="TranslationContext(name=org.apache.causeway.applib.mixins.layout.Object_downloadLayout#act())"/>
+<mml:attr name="facet" value="NamedFacetForParameterUsingReflection"/>
+<mml:attr name="originalText" value="Format"/>
+<mml:attr name="precedence" value="LOW"/>
+<mml:attr name="translated" value="Format"/>
+                            </mml:facet>
+                            <mml:facet id="org.apache.causeway.core.metamodel.facets.objectvalue.labelat.LabelAtFacet" fqcn="org.apache.causeway.core.metamodel.facets.fallback.LabelAtFacetFromLayoutConfiguration">
+<mml:attr name="facet" value="LabelAtFacetFromLayoutConfiguration"/>
+<mml:attr name="labelPosition" value="NOT_SPECIFIED"/>
+<mml:attr name="precedence" value="LOW"/>
+                            </mml:facet>
+                            <mml:facet id="org.apache.causeway.core.metamodel.facets.param.choices.ActionParameterChoicesFacet" fqcn="org.apache.causeway.core.metamodel.facets.param.choices.methodnum.ActionParameterChoicesFacetViaMethod">
+<mml:attr name="choicesType" value="SET"/>
+<mml:attr name="facet" value="ActionParameterChoicesFacetViaMethod"/>
+<mml:attr name="intent.choices2Act" value="CHOICES_OR_AUTOCOMPLETE"/>
+<mml:attr name="methods" value="public java.util.Set org.apache.causeway.applib.mixins.layout.Object_downloadLayout.choices2Act()"/>
+<mml:attr name="precedence" value="DEFAULT"/>
+                            </mml:facet>
+                            <mml:facet id="org.apache.causeway.core.metamodel.facets.param.defaults.ActionParameterDefaultsFacet" fqcn="org.apache.causeway.core.metamodel.facets.param.defaults.methodnum.ActionParameterDefaultsFacetViaMethod">
+<mml:attr name="facet" value="ActionParameterDefaultsFacetViaMethod"/>
+<mml:attr name="intent.default2Act" value="DEFAULTS"/>
+<mml:attr name="methods" value="public org.apache.causeway.applib.value.NamedWithMimeType$CommonMimeType org.apache.causeway.applib.mixins.layout.Object_downloadLayout.default2Act()"/>
+<mml:attr name="precedence" value="DEFAULT"/>
+                            </mml:facet>
+                            <mml:facet id="org.apache.causeway.core.metamodel.facets.param.parameter.depdef.ParameterDependentDefaultsFacet" fqcn="org.apache.causeway.core.metamodel.facets.param.parameter.depdef.ParameterDependentDefaultsFacetFromConfiguration">
+<mml:attr name="facet" value="ParameterDependentDefaultsFacetFromConfiguration"/>
+<mml:attr name="precedence" value="DEFAULT"/>
+<mml:attr name="value" value="UPDATE_DEPENDENT"/>
+                            </mml:facet>
+                        </mml:facets>
+                        <mml:type>org.apache.causeway.applib.value.NamedWithMimeType$CommonMimeType</mml:type>
+                    </mml:param>
+                </mml:params>
+            </mml:act>
+            <mml:act id="downloadMetamodelXml" mixedIn="true">
+                <mml:facets>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.action.explicit.ActionExplicitFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.explicit.ActionExplicitFacetForActionAnnotation">
+                        <mml:attr name="facet" value="ActionExplicitFacetForActionAnnotation"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionDomainEventFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionDomainEventFacet">
+                        <mml:attr name="eventType" value="org.apache.causeway.applib.mixins.metamodel.Object_downloadMetamodelXml.ActionDomainEvent"/>
+                        <mml:attr name="eventTypeOrigin" value="ANNOTATED_MEMBER"/>
+                        <mml:attr name="facet" value="ActionDomainEventFacet"/>
+                        <mml:attr name="interactionAdvisors" value="Validating, HidingOrShowing, DisablingOrEnabling"/>
+                        <mml:attr name="isPostable" value="true"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionInvocationFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionInvocationFacetForAction">
+                        <mml:attr name="declaringType" value="org.apache.causeway.applib.mixins.metamodel.Object_downloadMetamodelXml"/>
+                        <mml:attr name="eventType" value="org.apache.causeway.applib.mixins.metamodel.Object_downloadMetamodelXml.ActionDomainEvent"/>
+                        <mml:attr name="eventTypeOrigin" value="ANNOTATED_MEMBER"/>
+                        <mml:attr name="facet" value="ActionInvocationFacetForAction"/>
+                        <mml:attr name="intent.act" value="EXECUTE"/>
+                        <mml:attr name="isPostable" value="true"/>
+                        <mml:attr name="methods" value="public java.lang.Object org.apache.causeway.applib.mixins.metamodel.Object_downloadMetamodelXml.act(java.lang.String)"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="returnType" value="java.lang.Object"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.contributing.ContributingFacet">
+                        <mml:attr name="contributing" value="AS_ACTION"/>
+                        <mml:attr name="facet" value="ContributingFacetAbstract.1"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.position.ActionPositionFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.layout.ActionPositionFacetForActionLayoutAnnotation">
+                        <mml:attr name="facet" value="ActionPositionFacetForActionLayoutAnnotation"/>
+                        <mml:attr name="position" value="PANEL_DROPDOWN"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.prototype.PrototypeFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.prototype.PrototypeFacetForActionAnnotation">
+                        <mml:attr name="deploymentType" value="PRODUCTION"/>
+                        <mml:attr name="facet" value="PrototypeFacetForActionAnnotation"/>
+                        <mml:attr name="interactionAdvisors" value="HidingOrShowing"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.redirect.RedirectFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.layout.RedirectFacetFromActionLayoutAnnotation">
+                        <mml:attr name="facet" value="RedirectFacetFromActionLayoutAnnotation"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="redirect" value="AS_CONFIGURED"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.semantics.ActionSemanticsFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.semantics.ActionSemanticsFacetForActionAnnotation">
+                        <mml:attr name="facet" value="ActionSemanticsFacetForActionAnnotation"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="value" value="SAFE"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.all.described.MemberDescribedFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.layout.MemberDescribedFacetForActionLayoutAnnotation">
+                        <mml:attr name="context" value="TranslationContext(name=org.apache.causeway.applib.mixins.metamodel.Object_downloadMetamodelXml#act())"/>
+                        <mml:attr name="facet" value="MemberDescribedFacetForActionLayoutAnnotation"/>
+                        <mml:attr name="originalText" value="Downloads a representation of the framework's internal metamodel for this object's domain class"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="translated" value="Downloads a representation of the framework's internal metamodel for this object's domain class"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.all.named.MemberNamedFacet" fqcn="org.apache.causeway.core.metamodel.facets.all.named.MemberNamedFacetForStaticMemberName">
+                        <mml:attr name="context" value="TranslationContext(name=org.apache.causeway.applib.mixins.metamodel.Object_downloadMetamodelXml#act())"/>
+                        <mml:attr name="facet" value="MemberNamedFacetForStaticMemberName"/>
+                        <mml:attr name="originalText" value="Download Metamodel Xml"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="translated" value="Download Metamodel Xml"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.collections.collection.defaultview.DefaultViewFacet" fqcn="org.apache.causeway.core.metamodel.facets.collections.layout.DefaultViewFacetAsConfigured">
+                        <mml:attr name="facet" value="DefaultViewFacetAsConfigured"/>
+                        <mml:attr name="precedence" value="LOW"/>
+                        <mml:attr name="value" value="table"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.members.cssclassfa.CssClassFaFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.layout.CssClassFaFacetForActionLayoutAnnotation">
+                        <mml:attr name="classes" value="fa fa-fw fa-download"/>
+                        <mml:attr name="facet" value="CssClassFaFacetForActionLayoutAnnotation"/>
+                        <mml:attr name="position" value="LEFT"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.members.layout.group.LayoutGroupFacet" fqcn="org.apache.causeway.core.metamodel.facets.members.layout.group.LayoutGroupFacetFromActionLayoutAnnotation">
+                        <mml:attr name="facet" value="LayoutGroupFacetFromActionLayoutAnnotation"/>
+                        <mml:attr name="groupId" value="metadata"/>
+                        <mml:attr name="groupName" value="Metadata"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.members.layout.order.LayoutOrderFacet" fqcn="org.apache.causeway.core.metamodel.facets.members.layout.order.LayoutOrderFacetFromActionLayoutAnnotation">
+                        <mml:attr name="facet" value="LayoutOrderFacetFromActionLayoutAnnotation"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="sequence" value="700.2"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.object.promptStyle.PromptStyleFacet" fqcn="org.apache.causeway.core.metamodel.facets.object.promptStyle.PromptStyleFacetAsConfigured">
+                        <mml:attr name="facet" value="PromptStyleFacetAsConfigured"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="promptStyle" value="INLINE"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.object.tabledec.TableDecoratorFacet" fqcn="org.apache.causeway.core.metamodel.facets.collections.layout.tabledec.TableDecoratorFacetFromConfiguration">
+                        <mml:attr name="facet" value="TableDecoratorFacetFromConfiguration"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="value" value="org.apache.causeway.applib.annotation.TableDecorator.Default"/>
+                    </mml:facet>
+                </mml:facets>
+                <mml:returnType>java.lang.Object</mml:returnType>
+                <mml:params>
+                    <mml:param id="fileName" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="mml:scalarParam">
+                        <mml:facets>
+                            <mml:facet id="org.apache.causeway.core.metamodel.facets.all.described.ParamDescribedFacet" fqcn="org.apache.causeway.core.metamodel.facets.param.layout.ParamDescribedFacetForParameterLayoutAnnotation">
+<mml:attr name="context" value="TranslationContext(name=org.apache.causeway.applib.mixins.metamodel.Object_downloadMetamodelXml#act())"/>
+<mml:attr name="facet" value="ParamDescribedFacetForParameterLayoutAnnotation"/>
+<mml:attr name="originalText" value="File name extension can be omitted."/>
+<mml:attr name="precedence" value="DEFAULT"/>
+<mml:attr name="translated" value="File name extension can be omitted."/>
+                            </mml:facet>
+                            <mml:facet id="org.apache.causeway.core.metamodel.facets.all.named.ParamNamedFacet" fqcn="org.apache.causeway.core.metamodel.facets.param.layout.NamedFacetForParameterLayoutAnnotation">
+<mml:attr name="context" value="TranslationContext(name=org.apache.causeway.applib.mixins.metamodel.Object_downloadMetamodelXml#act())"/>
+<mml:attr name="facet" value="NamedFacetForParameterLayoutAnnotation"/>
+<mml:attr name="originalText" value="File name"/>
+<mml:attr name="precedence" value="DEFAULT"/>
+<mml:attr name="translated" value="File name"/>
+                            </mml:facet>
+                            <mml:facet id="org.apache.causeway.core.metamodel.facets.objectvalue.labelat.LabelAtFacet" fqcn="org.apache.causeway.core.metamodel.facets.fallback.LabelAtFacetFromLayoutConfiguration">
+<mml:attr name="facet" value="LabelAtFacetFromLayoutConfiguration"/>
+<mml:attr name="labelPosition" value="NOT_SPECIFIED"/>
+<mml:attr name="precedence" value="LOW"/>
+                            </mml:facet>
+                            <mml:facet id="org.apache.causeway.core.metamodel.facets.param.defaults.ActionParameterDefaultsFacet" fqcn="org.apache.causeway.core.metamodel.facets.param.defaults.methodnum.ActionParameterDefaultsFacetViaMethod">
+<mml:attr name="facet" value="ActionParameterDefaultsFacetViaMethod"/>
+<mml:attr name="intent.default0Act" value="DEFAULTS"/>
+<mml:attr name="methods" value="public java.lang.String org.apache.causeway.applib.mixins.metamodel.Object_downloadMetamodelXml.default0Act()"/>
+<mml:attr name="precedence" value="DEFAULT"/>
+                            </mml:facet>
+                            <mml:facet id="org.apache.causeway.core.metamodel.facets.param.parameter.depdef.ParameterDependentDefaultsFacet" fqcn="org.apache.causeway.core.metamodel.facets.param.parameter.depdef.ParameterDependentDefaultsFacetFromConfiguration">
+<mml:attr name="facet" value="ParameterDependentDefaultsFacetFromConfiguration"/>
+<mml:attr name="precedence" value="DEFAULT"/>
+<mml:attr name="value" value="UPDATE_DEPENDENT"/>
+                            </mml:facet>
+                        </mml:facets>
+                        <mml:type>java.lang.String</mml:type>
+                    </mml:param>
+                </mml:params>
+            </mml:act>
+            <mml:act id="inspectMetamodel" mixedIn="true">
+                <mml:facets>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.action.explicit.ActionExplicitFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.explicit.ActionExplicitFacetForActionAnnotation">
+                        <mml:attr name="facet" value="ActionExplicitFacetForActionAnnotation"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionDomainEventFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionDomainEventFacet">
+                        <mml:attr name="eventType" value="org.apache.causeway.core.metamodel.inspect.Object_inspectMetamodel.ActionDomainEvent"/>
+                        <mml:attr name="eventTypeOrigin" value="ANNOTATED_MEMBER"/>
+                        <mml:attr name="facet" value="ActionDomainEventFacet"/>
+                        <mml:attr name="interactionAdvisors" value="Validating, HidingOrShowing, DisablingOrEnabling"/>
+                        <mml:attr name="isPostable" value="true"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionInvocationFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionInvocationFacetForAction">
+                        <mml:attr name="declaringType" value="org.apache.causeway.core.metamodel.inspect.Object_inspectMetamodel"/>
+                        <mml:attr name="eventType" value="org.apache.causeway.core.metamodel.inspect.Object_inspectMetamodel.ActionDomainEvent"/>
+                        <mml:attr name="eventTypeOrigin" value="ANNOTATED_MEMBER"/>
+                        <mml:attr name="facet" value="ActionInvocationFacetForAction"/>
+                        <mml:attr name="intent.act" value="EXECUTE"/>
+                        <mml:attr name="isPostable" value="true"/>
+                        <mml:attr name="methods" value="public java.lang.Object org.apache.causeway.core.metamodel.inspect.Object_inspectMetamodel.act()"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="returnType" value="java.lang.Object"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.contributing.ContributingFacet">
+                        <mml:attr name="contributing" value="AS_ACTION"/>
+                        <mml:attr name="facet" value="ContributingFacetAbstract.1"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.position.ActionPositionFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.layout.ActionPositionFacetForActionLayoutAnnotation">
+                        <mml:attr name="facet" value="ActionPositionFacetForActionLayoutAnnotation"/>
+                        <mml:attr name="position" value="PANEL_DROPDOWN"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.prototype.PrototypeFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.prototype.PrototypeFacetForActionAnnotation">
+                        <mml:attr name="deploymentType" value="PRODUCTION"/>
+                        <mml:attr name="facet" value="PrototypeFacetForActionAnnotation"/>
+                        <mml:attr name="interactionAdvisors" value="HidingOrShowing"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.redirect.RedirectFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.layout.RedirectFacetFromActionLayoutAnnotation">
+                        <mml:attr name="facet" value="RedirectFacetFromActionLayoutAnnotation"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="redirect" value="AS_CONFIGURED"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.semantics.ActionSemanticsFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.semantics.ActionSemanticsFacetForActionAnnotation">
+                        <mml:attr name="facet" value="ActionSemanticsFacetForActionAnnotation"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="value" value="SAFE"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.all.described.MemberDescribedFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.layout.MemberDescribedFacetForActionLayoutAnnotation">
+                        <mml:attr name="context" value="TranslationContext(name=org.apache.causeway.core.metamodel.inspect.Object_inspectMetamodel#act())"/>
+                        <mml:attr name="facet" value="MemberDescribedFacetForActionLayoutAnnotation"/>
+                        <mml:attr name="originalText" value="Open up a view of the metamodel of this object's domain class"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="translated" value="Open up a view of the metamodel of this object's domain class"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.all.named.MemberNamedFacet" fqcn="org.apache.causeway.core.metamodel.facets.all.named.MemberNamedFacetForStaticMemberName">
+                        <mml:attr name="context" value="TranslationContext(name=org.apache.causeway.core.metamodel.inspect.Object_inspectMetamodel#act())"/>
+                        <mml:attr name="facet" value="MemberNamedFacetForStaticMemberName"/>
+                        <mml:attr name="originalText" value="Inspect Metamodel"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="translated" value="Inspect Metamodel"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.collections.collection.defaultview.DefaultViewFacet" fqcn="org.apache.causeway.core.metamodel.facets.collections.layout.DefaultViewFacetAsConfigured">
+                        <mml:attr name="facet" value="DefaultViewFacetAsConfigured"/>
+                        <mml:attr name="precedence" value="LOW"/>
+                        <mml:attr name="value" value="table"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.members.cssclassfa.CssClassFaFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.layout.CssClassFaFacetForActionLayoutAnnotation">
+                        <mml:attr name="classes" value="fa fa-fw fa-sitemap"/>
+                        <mml:attr name="facet" value="CssClassFaFacetForActionLayoutAnnotation"/>
+                        <mml:attr name="position" value="LEFT"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.members.layout.group.LayoutGroupFacet" fqcn="org.apache.causeway.core.metamodel.facets.members.layout.group.LayoutGroupFacetFromActionLayoutAnnotation">
+                        <mml:attr name="facet" value="LayoutGroupFacetFromActionLayoutAnnotation"/>
+                        <mml:attr name="groupId" value="metadata"/>
+                        <mml:attr name="groupName" value="Metadata"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.members.layout.order.LayoutOrderFacet" fqcn="org.apache.causeway.core.metamodel.facets.members.layout.order.LayoutOrderFacetFromActionLayoutAnnotation">
+                        <mml:attr name="facet" value="LayoutOrderFacetFromActionLayoutAnnotation"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="sequence" value="700.2.1"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.object.promptStyle.PromptStyleFacet" fqcn="org.apache.causeway.core.metamodel.facets.object.promptStyle.PromptStyleFacetAsConfigured">
+                        <mml:attr name="facet" value="PromptStyleFacetAsConfigured"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="promptStyle" value="INLINE"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.object.tabledec.TableDecoratorFacet" fqcn="org.apache.causeway.core.metamodel.facets.collections.layout.tabledec.TableDecoratorFacetFromConfiguration">
+                        <mml:attr name="facet" value="TableDecoratorFacetFromConfiguration"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="value" value="org.apache.causeway.applib.annotation.TableDecorator.Default"/>
+                    </mml:facet>
+                </mml:facets>
+                <mml:returnType>java.lang.Object</mml:returnType>
+                <mml:params/>
+            </mml:act>
+            <mml:act id="openRestApi" mixedIn="true">
+                <mml:facets>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.action.explicit.ActionExplicitFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.explicit.ActionExplicitFacetForActionAnnotation">
+                        <mml:attr name="facet" value="ActionExplicitFacetForActionAnnotation"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionDomainEventFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionDomainEventFacet">
+                        <mml:attr name="eventType" value="org.apache.causeway.applib.mixins.rest.Object_openRestApi.ActionDomainEvent"/>
+                        <mml:attr name="eventTypeOrigin" value="ANNOTATED_MEMBER"/>
+                        <mml:attr name="facet" value="ActionDomainEventFacet"/>
+                        <mml:attr name="interactionAdvisors" value="Validating, HidingOrShowing, DisablingOrEnabling"/>
+                        <mml:attr name="isPostable" value="true"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionInvocationFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionInvocationFacetForAction">
+                        <mml:attr name="declaringType" value="org.apache.causeway.applib.mixins.rest.Object_openRestApi"/>
+                        <mml:attr name="eventType" value="org.apache.causeway.applib.mixins.rest.Object_openRestApi.ActionDomainEvent"/>
+                        <mml:attr name="eventTypeOrigin" value="ANNOTATED_MEMBER"/>
+                        <mml:attr name="facet" value="ActionInvocationFacetForAction"/>
+                        <mml:attr name="intent.act" value="EXECUTE"/>
+                        <mml:attr name="isPostable" value="true"/>
+                        <mml:attr name="methods" value="public org.apache.causeway.applib.value.LocalResourcePath org.apache.causeway.applib.mixins.rest.Object_openRestApi.act()"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="returnType" value="org.apache.causeway.applib.value.LocalResourcePath"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.contributing.ContributingFacet">
+                        <mml:attr name="contributing" value="AS_ACTION"/>
+                        <mml:attr name="facet" value="ContributingFacetAbstract.1"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.position.ActionPositionFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.layout.ActionPositionFacetForActionLayoutAnnotation">
+                        <mml:attr name="facet" value="ActionPositionFacetForActionLayoutAnnotation"/>
+                        <mml:attr name="position" value="PANEL_DROPDOWN"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.prototype.PrototypeFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.prototype.PrototypeFacetForActionAnnotation">
+                        <mml:attr name="deploymentType" value="PRODUCTION"/>
+                        <mml:attr name="facet" value="PrototypeFacetForActionAnnotation"/>
+                        <mml:attr name="interactionAdvisors" value="HidingOrShowing"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.redirect.RedirectFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.layout.RedirectFacetFromActionLayoutAnnotation">
+                        <mml:attr name="facet" value="RedirectFacetFromActionLayoutAnnotation"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="redirect" value="AS_CONFIGURED"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.semantics.ActionSemanticsFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.semantics.ActionSemanticsFacetForActionAnnotation">
+                        <mml:attr name="facet" value="ActionSemanticsFacetForActionAnnotation"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="value" value="SAFE"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.all.described.MemberDescribedFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.layout.MemberDescribedFacetForActionLayoutAnnotation">
+                        <mml:attr name="context" value="TranslationContext(name=org.apache.causeway.applib.mixins.rest.Object_openRestApi#act())"/>
+                        <mml:attr name="facet" value="MemberDescribedFacetForActionLayoutAnnotation"/>
+                        <mml:attr name="originalText" value="Opens up a view of this object as represented in the (Restful Objects) REST API"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="translated" value="Opens up a view of this object as represented in the (Restful Objects) REST API"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.all.named.MemberNamedFacet" fqcn="org.apache.causeway.core.metamodel.facets.all.named.MemberNamedFacetForStaticMemberName">
+                        <mml:attr name="context" value="TranslationContext(name=org.apache.causeway.applib.mixins.rest.Object_openRestApi#act())"/>
+                        <mml:attr name="facet" value="MemberNamedFacetForStaticMemberName"/>
+                        <mml:attr name="originalText" value="Open Rest Api"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="translated" value="Open Rest Api"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.collections.collection.defaultview.DefaultViewFacet" fqcn="org.apache.causeway.core.metamodel.facets.collections.layout.DefaultViewFacetAsConfigured">
+                        <mml:attr name="facet" value="DefaultViewFacetAsConfigured"/>
+                        <mml:attr name="precedence" value="LOW"/>
+                        <mml:attr name="value" value="table"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.members.cssclassfa.CssClassFaFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.layout.CssClassFaFacetForActionLayoutAnnotation">
+                        <mml:attr name="classes" value="fa fa-fw fa-external-link-alt"/>
+                        <mml:attr name="facet" value="CssClassFaFacetForActionLayoutAnnotation"/>
+                        <mml:attr name="position" value="LEFT"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.members.layout.group.LayoutGroupFacet" fqcn="org.apache.causeway.core.metamodel.facets.members.layout.group.LayoutGroupFacetFromActionLayoutAnnotation">
+                        <mml:attr name="facet" value="LayoutGroupFacetFromActionLayoutAnnotation"/>
+                        <mml:attr name="groupId" value="metadata"/>
+                        <mml:attr name="groupName" value="Metadata"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.members.layout.order.LayoutOrderFacet" fqcn="org.apache.causeway.core.metamodel.facets.members.layout.order.LayoutOrderFacetFromActionLayoutAnnotation">
+                        <mml:attr name="facet" value="LayoutOrderFacetFromActionLayoutAnnotation"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="sequence" value="750.1"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.object.promptStyle.PromptStyleFacet" fqcn="org.apache.causeway.core.metamodel.facets.object.promptStyle.PromptStyleFacetAsConfigured">
+                        <mml:attr name="facet" value="PromptStyleFacetAsConfigured"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="promptStyle" value="INLINE"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.object.tabledec.TableDecoratorFacet" fqcn="org.apache.causeway.core.metamodel.facets.collections.layout.tabledec.TableDecoratorFacetFromConfiguration">
+                        <mml:attr name="facet" value="TableDecoratorFacetFromConfiguration"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="value" value="org.apache.causeway.applib.annotation.TableDecorator.Default"/>
+                    </mml:facet>
+                </mml:facets>
+                <mml:returnType>org.apache.causeway.applib.value.LocalResourcePath</mml:returnType>
+                <mml:params/>
+            </mml:act>
+            <mml:act id="rebuildMetamodel" mixedIn="true">
+                <mml:facets>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.action.explicit.ActionExplicitFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.explicit.ActionExplicitFacetForActionAnnotation">
+                        <mml:attr name="facet" value="ActionExplicitFacetForActionAnnotation"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionDomainEventFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionDomainEventFacet">
+                        <mml:attr name="eventType" value="org.apache.causeway.applib.mixins.metamodel.Object_rebuildMetamodel.ActionDomainEvent"/>
+                        <mml:attr name="eventTypeOrigin" value="ANNOTATED_MEMBER"/>
+                        <mml:attr name="facet" value="ActionDomainEventFacet"/>
+                        <mml:attr name="interactionAdvisors" value="Validating, HidingOrShowing, DisablingOrEnabling"/>
+                        <mml:attr name="isPostable" value="true"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionInvocationFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.invocation.ActionInvocationFacetForAction">
+                        <mml:attr name="declaringType" value="org.apache.causeway.applib.mixins.metamodel.Object_rebuildMetamodel"/>
+                        <mml:attr name="eventType" value="org.apache.causeway.applib.mixins.metamodel.Object_rebuildMetamodel.ActionDomainEvent"/>
+                        <mml:attr name="eventTypeOrigin" value="ANNOTATED_MEMBER"/>
+                        <mml:attr name="facet" value="ActionInvocationFacetForAction"/>
+                        <mml:attr name="intent.act" value="EXECUTE"/>
+                        <mml:attr name="isPostable" value="true"/>
+                        <mml:attr name="methods" value="public java.lang.Object org.apache.causeway.applib.mixins.metamodel.Object_rebuildMetamodel.act()"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="returnType" value="java.lang.Object"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.contributing.ContributingFacet">
+                        <mml:attr name="contributing" value="AS_ACTION"/>
+                        <mml:attr name="facet" value="ContributingFacetAbstract.1"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.position.ActionPositionFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.layout.ActionPositionFacetForActionLayoutAnnotation">
+                        <mml:attr name="facet" value="ActionPositionFacetForActionLayoutAnnotation"/>
+                        <mml:attr name="position" value="PANEL"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.prototype.PrototypeFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.prototype.PrototypeFacetForActionAnnotation">
+                        <mml:attr name="deploymentType" value="PRODUCTION"/>
+                        <mml:attr name="facet" value="PrototypeFacetForActionAnnotation"/>
+                        <mml:attr name="interactionAdvisors" value="HidingOrShowing"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.redirect.RedirectFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.layout.RedirectFacetFromActionLayoutAnnotation">
+                        <mml:attr name="facet" value="RedirectFacetFromActionLayoutAnnotation"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="redirect" value="AS_CONFIGURED"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.actions.semantics.ActionSemanticsFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.action.semantics.ActionSemanticsFacetForActionAnnotation">
+                        <mml:attr name="facet" value="ActionSemanticsFacetForActionAnnotation"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="value" value="IDEMPOTENT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.all.described.MemberDescribedFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.layout.MemberDescribedFacetForActionLayoutAnnotation">
+                        <mml:attr name="context" value="TranslationContext(name=org.apache.causeway.applib.mixins.metamodel.Object_rebuildMetamodel#act())"/>
+                        <mml:attr name="facet" value="MemberDescribedFacetForActionLayoutAnnotation"/>
+                        <mml:attr name="originalText" value="Rebuilds the framework's internal metamodel of this object's domain class"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="translated" value="Rebuilds the framework's internal metamodel of this object's domain class"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.all.named.MemberNamedFacet" fqcn="org.apache.causeway.core.metamodel.facets.all.named.MemberNamedFacetForStaticMemberName">
+                        <mml:attr name="context" value="TranslationContext(name=org.apache.causeway.applib.mixins.metamodel.Object_rebuildMetamodel#act())"/>
+                        <mml:attr name="facet" value="MemberNamedFacetForStaticMemberName"/>
+                        <mml:attr name="originalText" value="Rebuild Metamodel"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="translated" value="Rebuild Metamodel"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.collections.collection.defaultview.DefaultViewFacet" fqcn="org.apache.causeway.core.metamodel.facets.collections.layout.DefaultViewFacetAsConfigured">
+                        <mml:attr name="facet" value="DefaultViewFacetAsConfigured"/>
+                        <mml:attr name="precedence" value="LOW"/>
+                        <mml:attr name="value" value="table"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.members.cssclassfa.CssClassFaFacet" fqcn="org.apache.causeway.core.metamodel.facets.actions.layout.CssClassFaFacetForActionLayoutAnnotation">
+                        <mml:attr name="classes" value="fa fa-fw fa-sync"/>
+                        <mml:attr name="facet" value="CssClassFaFacetForActionLayoutAnnotation"/>
+                        <mml:attr name="position" value="LEFT"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.members.layout.group.LayoutGroupFacet" fqcn="org.apache.causeway.core.metamodel.facets.members.layout.group.LayoutGroupFacetFromActionLayoutAnnotation">
+                        <mml:attr name="facet" value="LayoutGroupFacetFromActionLayoutAnnotation"/>
+                        <mml:attr name="groupId" value="metadata"/>
+                        <mml:attr name="groupName" value="Metadata"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.members.layout.order.LayoutOrderFacet" fqcn="org.apache.causeway.core.metamodel.facets.members.layout.order.LayoutOrderFacetFromActionLayoutAnnotation">
+                        <mml:attr name="facet" value="LayoutOrderFacetFromActionLayoutAnnotation"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="sequence" value="800.1"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.object.promptStyle.PromptStyleFacet" fqcn="org.apache.causeway.core.metamodel.facets.object.promptStyle.PromptStyleFacetAsConfigured">
+                        <mml:attr name="facet" value="PromptStyleFacetAsConfigured"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="promptStyle" value="INLINE"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.object.tabledec.TableDecoratorFacet" fqcn="org.apache.causeway.core.metamodel.facets.collections.layout.tabledec.TableDecoratorFacetFromConfiguration">
+                        <mml:attr name="facet" value="TableDecoratorFacetFromConfiguration"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="value" value="org.apache.causeway.applib.annotation.TableDecorator.Default"/>
+                    </mml:facet>
+                </mml:facets>
+                <mml:returnType>java.lang.Object</mml:returnType>
+                <mml:params/>
+            </mml:act>
+        </mml:actions>
+    </mml:domainClassDto>
+    <mml:domainClassDto id="org.apache.causeway.testdomain.model.good.ProperGenericInterfaceImpl">
+        <mml:facets>
+            <mml:facet id="org.apache.causeway.core.metamodel.facets.all.named.MemberNamedFacet" fqcn="org.apache.causeway.core.metamodel.facets.all.named.MemberNamedFacetForStaticMemberName">
+                <mml:attr name="context" value="TranslationContext(name=org.apache.causeway.testdomain.model.good.ProperGenericInterfaceImpl#)"/>
+                <mml:attr name="facet" value="MemberNamedFacetForStaticMemberName"/>
+                <mml:attr name="originalText" value="Proper Generic Interface Impl"/>
+                <mml:attr name="precedence" value="DEFAULT"/>
+                <mml:attr name="translated" value="Proper Generic Interface Impl"/>
+            </mml:facet>
+            <mml:facet id="org.apache.causeway.core.metamodel.facets.all.named.ObjectNamedFacet" fqcn="org.apache.causeway.core.metamodel.facets.all.named.ObjectNamedFacetSynthesized">
+                <mml:attr name="context" value="TranslationContext(name=org.apache.causeway.testdomain.model.good.ProperGenericInterfaceImpl#)"/>
+                <mml:attr name="facet" value="ObjectNamedFacetSynthesized"/>
+                <mml:attr name="hasNoun" value="true"/>
+                <mml:attr name="originalText" value="Optional[Proper Generic Interface Impl]"/>
+                <mml:attr name="precedence" value="SYNTHESIZED"/>
+                <mml:attr name="translated" value="Optional[Proper Generic Interface Impl]"/>
+            </mml:facet>
+            <mml:facet id="org.apache.causeway.core.metamodel.facets.object.callbacks.CreatedLifecycleEventFacet" fqcn="org.apache.causeway.core.metamodel.facets.object.callbacks.CreatedLifecycleEventFacetForDomainObjectAnnotation">
+                <mml:attr name="facet" value="CreatedLifecycleEventFacetForDomainObjectAnnotation"/>
+                <mml:attr name="precedence" value="DEFAULT"/>
+                <mml:attr name="value" value="org.apache.causeway.applib.events.lifecycle.ObjectCreatedEvent.Default"/>
+            </mml:facet>
+            <mml:facet id="org.apache.causeway.core.metamodel.facets.object.callbacks.LoadedLifecycleEventFacet" fqcn="org.apache.causeway.core.metamodel.facets.object.callbacks.LoadedLifecycleEventFacetForDomainObjectAnnotation">
+                <mml:attr name="facet" value="LoadedLifecycleEventFacetForDomainObjectAnnotation"/>
+                <mml:attr name="precedence" value="DEFAULT"/>
+                <mml:attr name="value" value="org.apache.causeway.applib.events.lifecycle.ObjectLoadedEvent.Default"/>
+            </mml:facet>
+            <mml:facet id="org.apache.causeway.core.metamodel.facets.object.callbacks.PersistedLifecycleEventFacet" fqcn="org.apache.causeway.core.metamodel.facets.object.callbacks.PersistedLifecycleEventFacetForDomainObjectAnnotation">
+                <mml:attr name="facet" value="PersistedLifecycleEventFacetForDomainObjectAnnotation"/>
+                <mml:attr name="precedence" value="DEFAULT"/>
+                <mml:attr name="value" value="org.apache.causeway.applib.events.lifecycle.ObjectPersistedEvent.Default"/>
+            </mml:facet>
+            <mml:facet id="org.apache.causeway.core.metamodel.facets.object.callbacks.PersistingLifecycleEventFacet" fqcn="org.apache.causeway.core.metamodel.facets.object.callbacks.PersistingLifecycleEventFacetForDomainObjectAnnotation">
+                <mml:attr name="facet" value="PersistingLifecycleEventFacetForDomainObjectAnnotation"/>
+                <mml:attr name="precedence" value="DEFAULT"/>
+                <mml:attr name="value" value="org.apache.causeway.applib.events.lifecycle.ObjectPersistingEvent.Default"/>
+            </mml:facet>
+            <mml:facet id="org.apache.causeway.core.metamodel.facets.object.callbacks.RemovingLifecycleEventFacet" fqcn="org.apache.causeway.core.metamodel.facets.object.callbacks.RemovingLifecycleEventFacetForDomainObjectAnnotation">
+                <mml:attr name="facet" value="RemovingLifecycleEventFacetForDomainObjectAnnotation"/>
+                <mml:attr name="precedence" value="DEFAULT"/>
+                <mml:attr name="value" value="org.apache.causeway.applib.events.lifecycle.ObjectRemovingEvent.Default"/>
+            </mml:facet>
+            <mml:facet id="org.apache.causeway.core.metamodel.facets.object.callbacks.UpdatedLifecycleEventFacet" fqcn="org.apache.causeway.core.metamodel.facets.object.callbacks.UpdatedLifecycleEventFacetForDomainObjectAnnotation">
+                <mml:attr name="facet" value="UpdatedLifecycleEventFacetForDomainObjectAnnotation"/>
+                <mml:attr name="precedence" value="DEFAULT"/>
+                <mml:attr name="value" value="org.apache.causeway.applib.events.lifecycle.ObjectUpdatedEvent.Default"/>
+            </mml:facet>
+            <mml:facet id="org.apache.causeway.core.metamodel.facets.object.callbacks.UpdatingLifecycleEventFacet" fqcn="org.apache.causeway.core.metamodel.facets.object.callbacks.UpdatingLifecycleEventFacetForDomainObjectAnnotation">
+                <mml:attr name="facet" value="UpdatingLifecycleEventFacetForDomainObjectAnnotation"/>
+                <mml:attr name="precedence" value="DEFAULT"/>
+                <mml:attr name="value" value="org.apache.causeway.applib.events.lifecycle.ObjectUpdatingEvent.Default"/>
+            </mml:facet>
+            <mml:facet id="org.apache.causeway.core.metamodel.facets.object.grid.GridFacet" fqcn="org.apache.causeway.core.metamodel.facets.object.grid.GridFacetDefault">
+                <mml:attr name="facet" value="GridFacetDefault"/>
+                <mml:attr name="precedence" value="DEFAULT"/>
+            </mml:facet>
+            <mml:facet id="org.apache.causeway.core.metamodel.facets.object.hidden.HiddenTypeFacet" fqcn="org.apache.causeway.core.metamodel.facets.object.hidden.HiddenTypeFacetFromAuthorization">
+                <mml:attr name="facet" value="HiddenTypeFacetFromAuthorization"/>
+                <mml:attr name="interactionAdvisors" value="HidingOrShowing"/>
+                <mml:attr name="precedence" value="HIGH"/>
+            </mml:facet>
+            <mml:facet id="org.apache.causeway.core.metamodel.facets.object.objectvalidprops.ObjectValidPropertiesFacet" fqcn="org.apache.causeway.core.metamodel.facets.object.objectvalidprops.impl.ObjectValidPropertiesFacetImpl">
+                <mml:attr name="facet" value="ObjectValidPropertiesFacetImpl"/>
+                <mml:attr name="interactionAdvisors" value="Validating"/>
+                <mml:attr name="precedence" value="DEFAULT"/>
+            </mml:facet>
+            <mml:facet id="org.apache.causeway.core.metamodel.facets.object.paged.PagedFacet" fqcn="org.apache.causeway.core.metamodel.facets.fallback.PagedFacetFromConfiguration">
+                <mml:attr name="facet" value="PagedFacetFromConfiguration"/>
+                <mml:attr name="precedence" value="INFERRED"/>
+                <mml:attr name="value" value="25"/>
+            </mml:facet>
+            <mml:facet id="org.apache.causeway.core.metamodel.facets.object.publish.entitychange.EntityChangePublishingFacet" fqcn="org.apache.causeway.core.metamodel.facets.object.domainobject.entitychangepublishing.EntityChangePublishingFacetForDomainObjectAnnotationAsConfigured">
+                <mml:attr name="facet" value="EntityChangePublishingFacetForDomainObjectAnnotationAsConfigured"/>
+                <mml:attr name="precedence" value="DEFAULT"/>
+            </mml:facet>
+            <mml:facet id="org.apache.causeway.core.metamodel.facets.object.tabledec.TableDecoratorFacet" fqcn="org.apache.causeway.core.metamodel.facets.object.domainobjectlayout.tabledec.TableDecoratorFacetFromConfiguration">
+                <mml:attr name="facet" value="TableDecoratorFacetFromConfiguration"/>
+                <mml:attr name="precedence" value="DEFAULT"/>
+                <mml:attr name="value" value="org.apache.causeway.applib.annotation.TableDecorator.Default"/>
+            </mml:facet>
+            <mml:facet id="org.apache.causeway.core.metamodel.facets.object.viewmodel.ViewModelFacet" fqcn="org.apache.causeway.core.metamodel.facets.object.viewmodel.ViewModelFacetForDomainObjectAnnotation">
+                <mml:attr name="facet" value="ViewModelFacetForDomainObjectAnnotation"/>
+                <mml:attr name="precedence" value="LOW"/>
+            </mml:facet>
+            <mml:facet id="org.apache.causeway.core.metamodel.postprocessors.allbutparam.authorization.AuthorizationFacet" fqcn="org.apache.causeway.core.metamodel.postprocessors.allbutparam.authorization.AuthorizationFacetImpl">
+                <mml:attr name="facet" value="AuthorizationFacetImpl"/>
+                <mml:attr name="interactionAdvisors" value="HidingOrShowing, DisablingOrEnabling"/>
+                <mml:attr name="precedence" value="DEFAULT"/>
+            </mml:facet>
+        </mml:facets>
+        <mml:properties>
+            <mml:prop id="value" mixedIn="false">
+                <mml:facets>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.object.promptStyle.PromptStyleFacet" fqcn="org.apache.causeway.core.metamodel.facets.object.promptStyle.PromptStyleFacetAsConfigured">
+                        <mml:attr name="facet" value="PromptStyleFacetAsConfigured"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                        <mml:attr name="promptStyle" value="INLINE"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.objectvalue.labelat.LabelAtFacet" fqcn="org.apache.causeway.core.metamodel.facets.fallback.LabelAtFacetFromLayoutConfiguration">
+                        <mml:attr name="facet" value="LabelAtFacetFromLayoutConfiguration"/>
+                        <mml:attr name="labelPosition" value="NOT_SPECIFIED"/>
+                        <mml:attr name="precedence" value="LOW"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.objectvalue.typicallen.TypicalLengthFacet" fqcn="org.apache.causeway.core.metamodel.facets.properties.typicallen.fromtype.TypicalLengthFacetOnPropertyFromType">
+                        <mml:attr name="facet" value="TypicalLengthFacetOnPropertyFromType"/>
+                        <mml:attr name="precedence" value="INFERRED"/>
+                        <mml:attr name="typicalLength" value="25"/>
+                        <mml:attr name="typicalLengthFacet" value="org.apache.causeway.core.metamodel.facets.object.value.TypicalLengthFacetFromValueFacet"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.propcoll.accessor.PropertyOrCollectionAccessorFacet" fqcn="org.apache.causeway.core.metamodel.facets.properties.accessor.PropertyAccessorFacetViaAccessor">
+                        <mml:attr name="declaringType" value="org.apache.causeway.testdomain.model.good.ProperGenericInterfaceImpl"/>
+                        <mml:attr name="facet" value="PropertyAccessorFacetViaAccessor"/>
+                        <mml:attr name="intent.getValue" value="ACCESSOR"/>
+                        <mml:attr name="methods" value="public java.lang.String org.apache.causeway.testdomain.model.good.ProperGenericInterfaceImpl.getValue()"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.properties.property.modify.PropertyDomainEventFacet" fqcn="org.apache.causeway.core.metamodel.facets.properties.property.modify.PropertyDomainEventFacet">
+                        <mml:attr name="eventType" value="org.apache.causeway.applib.events.domain.PropertyDomainEvent.Default"/>
+                        <mml:attr name="eventTypeOrigin" value="DEFAULT"/>
+                        <mml:attr name="facet" value="PropertyDomainEventFacet"/>
+                        <mml:attr name="getterFacet" value="org.apache.causeway.core.metamodel.facets.properties.accessor.PropertyAccessorFacetViaAccessor"/>
+                        <mml:attr name="interactionAdvisors" value="Validating, HidingOrShowing, DisablingOrEnabling"/>
+                        <mml:attr name="isPostable" value="true"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.properties.update.clear.PropertyClearFacet" fqcn="org.apache.causeway.core.metamodel.facets.properties.property.modify.PropertyModifyFacetForClearing">
+                        <mml:attr name="clearFacet" value="org.apache.causeway.core.metamodel.facets.properties.update.clear.PropertyClearFacetViaSetterMethod"/>
+                        <mml:attr name="eventType" value="org.apache.causeway.applib.events.domain.PropertyDomainEvent.Default"/>
+                        <mml:attr name="eventTypeOrigin" value="DEFAULT"/>
+                        <mml:attr name="facet" value="PropertyModifyFacetForClearing"/>
+                        <mml:attr name="getterFacet" value="org.apache.causeway.core.metamodel.facets.properties.accessor.PropertyAccessorFacetViaAccessor"/>
+                        <mml:attr name="isPostable" value="true"/>
+                        <mml:attr name="precedence" value="DEFAULT"/>
+                    </mml:facet>
+                    <mml:facet id="org.apache.causeway.core.metamodel.facets.properties.update.init.PropertyInitializationFacet" fqcn="org.apache.causeway.core.metamodel.facets.properties.update.init.PropertyInitializationFacetViaSetterMethod">
+                        <mml:attr name="facet" value="PropertyInitializationFacetViaSetterMethod"/>
+                        <mml:attr name="intent.setValue" value="MODIFY_PROPERTY"/>
+                        <mml:attr name="methods" value="public void org.apache.causeway.testdomain.model.good.ProperGenericInterfaceImpl.setValue(java.lang.String)"/>
                         <mml:attr name="precedence" value="DEFAULT"/>
                     </mml:facet>
                     <mml:facet id="org.apache.causeway.core.metamodel.facets.properties.update.modify.PropertySetterFacet" fqcn="org.apache.causeway.core.metamodel.facets.properties.property.modify.PropertyModifyFacetForSetting">
diff --git a/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericInterface.java b/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericAbstract.java
similarity index 80%
copy from regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericInterface.java
copy to regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericAbstract.java
index 144f5122dd..dfa6c75a31 100644
--- a/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericInterface.java
+++ b/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericAbstract.java
@@ -18,9 +18,13 @@
  */
 package org.apache.causeway.testdomain.model.good;
 
-public interface ProperGenericInterface<T> {
+import org.springframework.lang.Nullable;
 
-    T getValue();
-    void setValue(T prop);
+public abstract class ProperGenericAbstract<T> {
+
+    abstract T getValue();
+    abstract void setValue(T prop);
+
+    abstract T sampleAction(@Nullable final T value);
 
 }
diff --git a/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericImpl.java b/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericAbstractImpl.java
similarity index 87%
copy from regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericImpl.java
copy to regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericAbstractImpl.java
index 9250ecc454..a28f599307 100644
--- a/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericImpl.java
+++ b/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericAbstractImpl.java
@@ -26,11 +26,16 @@ import lombok.Getter;
 import lombok.Setter;
 
 @DomainObject(nature = Nature.VIEW_MODEL)
-public class ProperGenericImpl
-implements ProperGenericInterface<String> {
+public class ProperGenericAbstractImpl
+extends ProperGenericAbstract<String> {
 
     @Property
     @Getter @Setter
     private String value = "aValue";
 
+    @Override
+    public String sampleAction(final String value) {
+        return value;
+    }
+
 }
diff --git a/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericInterface.java b/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericInterface.java
index 144f5122dd..a942508643 100644
--- a/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericInterface.java
+++ b/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericInterface.java
@@ -18,9 +18,13 @@
  */
 package org.apache.causeway.testdomain.model.good;
 
+import org.springframework.lang.Nullable;
+
 public interface ProperGenericInterface<T> {
 
     T getValue();
     void setValue(T prop);
 
+    T sampleAction(@Nullable final T value);
+
 }
diff --git a/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericImpl.java b/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericInterfaceImpl.java
similarity index 90%
rename from regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericImpl.java
rename to regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericInterfaceImpl.java
index 9250ecc454..aba0af47a6 100644
--- a/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericImpl.java
+++ b/regressiontests/stable/src/main/java/org/apache/causeway/testdomain/model/good/ProperGenericInterfaceImpl.java
@@ -26,11 +26,16 @@ import lombok.Getter;
 import lombok.Setter;
 
 @DomainObject(nature = Nature.VIEW_MODEL)
-public class ProperGenericImpl
+public class ProperGenericInterfaceImpl
 implements ProperGenericInterface<String> {
 
     @Property
     @Getter @Setter
     private String value = "aValue";
 
+    @Override
+    public String sampleAction(final String value) {
+        return value;
+    }
+
 }