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

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


The following commit(s) were added to refs/heads/master by this push:
     new f9f9aef6e4 ISIS-3293: revert viewmodel changes from prev. commit; 
support constructor inject semantics
f9f9aef6e4 is described below

commit f9f9aef6e471e886aee3f937a714017b1a5b58b7
Author: Andi Huber <[email protected]>
AuthorDate: Thu Nov 24 16:44:14 2022 +0100

    ISIS-3293: revert viewmodel changes from prev. commit; support
    constructor inject semantics
---
 .../appfeatui/ApplicationFeatureViewModel.java     |  2 +-
 .../services/appfeatui/ApplicationNamespace.java   | 15 ++---
 .../applib/services/appfeatui/ApplicationType.java | 18 ++++--
 .../services/appfeatui/ApplicationTypeAction.java  | 16 ++---
 .../appfeatui/ApplicationTypeCollection.java       | 16 ++---
 .../appfeatui/ApplicationTypeProperty.java         | 17 ++---
 commons/src/main/java/module-info.java             |  1 +
 .../commons/internal/reflection/_ClassCache.java   |  9 +++
 .../progmodel/ProgrammingModelConstants.java       | 39 ++++++++----
 .../ViewModelFacetForViewModelInterface.java       | 74 ++++++++++++++++++----
 .../dom/domain/_interactions/InteractionDtoVm.java |  2 +
 .../feature/api/ApplicationFeatureChoices.java     |  1 +
 .../dom/mixins/perms/UserPermissionViewModel.java  |  1 +
 13 files changed, 147 insertions(+), 64 deletions(-)

diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationFeatureViewModel.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationFeatureViewModel.java
index ffe4f9d99c..ed37d3dd7e 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationFeatureViewModel.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationFeatureViewModel.java
@@ -90,7 +90,7 @@ public abstract class ApplicationFeatureViewModel implements 
ViewModel {
 
         if(featureId.getSort().isNamespace()) {
             _Assert.assertEquals(vmClass, ApplicationNamespace.class);
-            return 
factoryService.viewModel(ApplicationNamespace.of(featureId));
+            return factoryService.viewModel(new 
ApplicationNamespace(featureId));
         }
 
         return factoryService.viewModel(vmClass,
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationNamespace.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationNamespace.java
index 54d4820fb3..ef2588d797 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationNamespace.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationNamespace.java
@@ -25,6 +25,7 @@ import java.lang.annotation.Target;
 import java.util.List;
 import java.util.SortedSet;
 
+import javax.inject.Inject;
 import javax.inject.Named;
 
 import org.apache.causeway.applib.CausewayModuleApplib;
@@ -48,19 +49,17 @@ public class ApplicationNamespace extends 
ApplicationFeatureViewModel {
 
     public static abstract class CollectionDomainEvent<T> extends 
ApplicationFeatureViewModel.CollectionDomainEvent<ApplicationNamespace, T> {}
 
-    // -- CONSTRUCTION
+    // -- CONSTRUCTORS
 
+    public ApplicationNamespace() { }
+    public ApplicationNamespace(final ApplicationFeatureId featureId) {
+        super(featureId);
+    }
+    @Inject
     public ApplicationNamespace(final String memento) {
         super(memento);
     }
 
-    public static ApplicationNamespace of(final ApplicationFeatureId 
featureId) {
-        return new ApplicationNamespace(featureId);
-    }
-    private ApplicationNamespace(final ApplicationFeatureId featureId) {
-        super(featureId);
-    }
-
     // -- CONTENTS (collection, for namespaces only)
 
     @Collection(
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationType.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationType.java
index 121774c658..a528b2ba52 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationType.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationType.java
@@ -25,6 +25,7 @@ import java.lang.annotation.Target;
 import java.util.List;
 import java.util.SortedSet;
 
+import javax.inject.Inject;
 import javax.inject.Named;
 
 import org.apache.causeway.applib.CausewayModuleApplib;
@@ -51,17 +52,20 @@ public class ApplicationType extends 
ApplicationFeatureViewModel {
     public static abstract class CollectionDomainEvent<T>
             extends 
ApplicationFeatureViewModel.CollectionDomainEvent<ApplicationType, T> {}
 
-    // -- CONSTRUCTION
 
+
+    // -- constructors
+
+    public ApplicationType() { }
+    public ApplicationType(final ApplicationFeatureId featureId) {
+        super(featureId);
+    }
+    @Inject
     public ApplicationType(final String memento) {
         super(memento);
     }
-    public ApplicationType of(final ApplicationFeatureId featureId) {
-        return new ApplicationType(featureId);
-    }
-    private ApplicationType(final ApplicationFeatureId featureId) {
-        super(featureId);
-    }
+
+
 
     // -- actions (collection)
 
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationTypeAction.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationTypeAction.java
index 028884df2f..6949732a87 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationTypeAction.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationTypeAction.java
@@ -23,6 +23,7 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+import javax.inject.Inject;
 import javax.inject.Named;
 
 import org.apache.causeway.applib.CausewayModuleApplib;
@@ -47,17 +48,16 @@ public class ApplicationTypeAction extends 
ApplicationTypeMember {
 
     public static abstract class PropertyDomainEvent<T> extends 
ApplicationTypeMember.PropertyDomainEvent<ApplicationTypeAction, T> {}
 
-    // -- CONSTRUCTION
-
+    // -- constructors
+    public ApplicationTypeAction() { }
+    public ApplicationTypeAction(final ApplicationFeatureId featureId) {
+        super(featureId);
+    }
+    @Inject
     public ApplicationTypeAction(final String memento) {
         super(memento);
     }
-    public ApplicationTypeAction of(final ApplicationFeatureId featureId) {
-        return new ApplicationTypeAction(featureId);
-    }
-    private ApplicationTypeAction(final ApplicationFeatureId featureId) {
-        super(featureId);
-    }
+
 
     // -- returnTypeName (property)
 
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationTypeCollection.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationTypeCollection.java
index db525c646f..85eaf3a5b1 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationTypeCollection.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationTypeCollection.java
@@ -22,6 +22,7 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+import javax.inject.Inject;
 import javax.inject.Named;
 
 import org.apache.causeway.applib.CausewayModuleApplib;
@@ -45,17 +46,16 @@ public class ApplicationTypeCollection extends 
ApplicationTypeMember {
 
     public static abstract class PropertyDomainEvent<T> extends 
ApplicationTypeMember.PropertyDomainEvent<ApplicationTypeCollection, T> {}
 
-    // -- CONSTRUCTION
-
+    // -- constructors
+    public ApplicationTypeCollection() {}
+    public ApplicationTypeCollection(final ApplicationFeatureId featureId) {
+        super(featureId);
+    }
+    @Inject
     public ApplicationTypeCollection(final String memento) {
         super(memento);
     }
-    public ApplicationTypeCollection of(final ApplicationFeatureId featureId) {
-        return new ApplicationTypeCollection(featureId);
-    }
-    private ApplicationTypeCollection(final ApplicationFeatureId featureId) {
-        super(featureId);
-    }
+
 
     // -- elementType
 
diff --git 
a/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationTypeProperty.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationTypeProperty.java
index 7fdcc2dde2..b80605b23e 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationTypeProperty.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationTypeProperty.java
@@ -23,6 +23,7 @@ import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+import javax.inject.Inject;
 import javax.inject.Named;
 
 import org.apache.causeway.applib.CausewayModuleApplib;
@@ -50,17 +51,17 @@ public class ApplicationTypeProperty extends 
ApplicationTypeMember {
 
     public static abstract class PropertyDomainEvent<T> extends 
ApplicationTypeMember.PropertyDomainEvent<ApplicationTypeProperty, T> {}
 
-    // -- CONSTRUCTION
-
+    // -- constructors
+    public ApplicationTypeProperty() { }
+    public ApplicationTypeProperty(final ApplicationFeatureId featureId) {
+        super(featureId);
+    }
+    @Inject
     public ApplicationTypeProperty(final String memento) {
         super(memento);
     }
-    public ApplicationTypeProperty of(final ApplicationFeatureId featureId) {
-        return new ApplicationTypeProperty(featureId);
-    }
-    private ApplicationTypeProperty(final ApplicationFeatureId featureId) {
-        super(featureId);
-    }
+
+
 
     // -- returnType
 
diff --git a/commons/src/main/java/module-info.java 
b/commons/src/main/java/module-info.java
index aebeb4b206..2491d567a3 100644
--- a/commons/src/main/java/module-info.java
+++ b/commons/src/main/java/module-info.java
@@ -71,6 +71,7 @@ module org.apache.causeway.commons {
     requires transitive spring.beans;
     requires transitive spring.context;
     requires transitive spring.core;
+    requires java.inject;
 
     // JAXB JUnit test
     opens org.apache.causeway.commons.internal.resources to java.xml.bind;
diff --git 
a/commons/src/main/java/org/apache/causeway/commons/internal/reflection/_ClassCache.java
 
b/commons/src/main/java/org/apache/causeway/commons/internal/reflection/_ClassCache.java
index 5acc34abdf..773cb2cb7f 100644
--- 
a/commons/src/main/java/org/apache/causeway/commons/internal/reflection/_ClassCache.java
+++ 
b/commons/src/main/java/org/apache/causeway/commons/internal/reflection/_ClassCache.java
@@ -27,6 +27,9 @@ import java.util.Optional;
 import java.util.function.Predicate;
 import java.util.stream.Stream;
 
+import javax.inject.Inject;
+
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.lang.Nullable;
 import org.springframework.util.ReflectionUtils;
 
@@ -82,6 +85,12 @@ public final class _ClassCache implements AutoCloseable {
                 inspectType(type).publicConstructorsByKey.values()));
     }
 
+    public <T> Can<Constructor<T>> 
getPublicConstructorsWithInjectSemantics(final Class<T> type) {
+        return getPublicConstructors(type)
+                .filter(con->_Annotations.synthesize(con, 
Inject.class).isPresent()
+                        || _Annotations.synthesize(con, 
Autowired.class).map(annot->annot.required()).orElse(false));
+    }
+
     public Optional<Constructor<?>> lookupPublicConstructor(final Class<?> 
type, final Class<?>[] paramTypes) {
         return Optional.ofNullable(lookupConstructor(false, type, paramTypes));
     }
diff --git 
a/core/config/src/main/java/org/apache/causeway/core/config/progmodel/ProgrammingModelConstants.java
 
b/core/config/src/main/java/org/apache/causeway/core/config/progmodel/ProgrammingModelConstants.java
index 8f30c8aa67..bfc6853837 100644
--- 
a/core/config/src/main/java/org/apache/causeway/core/config/progmodel/ProgrammingModelConstants.java
+++ 
b/core/config/src/main/java/org/apache/causeway/core/config/progmodel/ProgrammingModelConstants.java
@@ -482,8 +482,13 @@ public final class ProgrammingModelConstants {
         VIEWMODEL_CONFLICTING_SERIALIZATION_STRATEGIES(
                 "${type}: has multiple incompatible annotations/interfaces 
indicating that "
                 + "it is a recreatable object of some sort (${facetA} and 
${facetB})"),
+        VIEWMODEL_MULTIPLE_CONSTRUCTORS_WITH_INJECT_SEMANTICS(
+                "${type}: ViewModel contract violation: there must be at most 
one public constructor that has inject semantics, "
+                + "but found ${found}. "
+                + "See " + 
org.apache.causeway.applib.ViewModel.class.getName() + " java-doc for 
details."),
         VIEWMODEL_MISSING_OR_MULTIPLE_PUBLIC_CONSTRUCTORS(
-                "${type}: ViewModel contract violation: there must be exactly 
one public constructor. "
+                "${type}: ViewModel contract violation: in absence of inject 
semantics there must be exactly one public constructor, "
+                + "but found ${found}. "
                 + "See " + 
org.apache.causeway.applib.ViewModel.class.getName() + " java-doc for 
details."),
         VIEWMODEL_MISSING_SERIALIZATION_STRATEGY(
                 "${type}: Missing ViewModel serialization strategy 
encountered; "
@@ -539,22 +544,32 @@ public final class ProgrammingModelConstants {
         }
     }
 
+    /**
+     * violation of view-model contract should be covered by meta-model 
validation
+     */
     public static enum ViewmodelConstructor {
-        PUBLIC_ANY_ARGS {
-
-            @Override
-            public <T> Optional<Constructor<T>> get(final Class<T> cls) {
-                // violation of view-model contract should be covered by 
meta-model validation
+        PUBLIC_WITH_INJECT_SEMANTICS {
+            @Override public <T> Can<Constructor<T>> getAll(final Class<T> 
cls) {
                 return Try.call(()->
                     _ClassCache.getInstance()
-                        .getPublicConstructors(cls)
-                        .getSingleton().orElse(null))
-                        .getValue();
+                        .getPublicConstructorsWithInjectSemantics(cls))
+                        .getValue()
+                        .orElse(Can.empty());
+            }
+        },
+        PUBLIC_ANY {
+            @Override public <T> Can<Constructor<T>> getAll(final Class<T> 
cls) {
+                return Try.call(()->
+                    _ClassCache.getInstance()
+                        .getPublicConstructors(cls))
+                        .getValue()
+                        .orElse(Can.empty());
             }
-
         };
-        public abstract <T> Optional<Constructor<T>> get(Class<T> 
correspondingClass);
-
+        public <T> Optional<Constructor<T>> getFirst(final Class<T> cls) {
+            return getAll(cls).getFirst();
+        }
+        public abstract <T> Can<Constructor<T>> getAll(Class<T> cls);
     }
 
     /**
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetForViewModelInterface.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetForViewModelInterface.java
index 32af74c142..4b3da2b6bc 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetForViewModelInterface.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/viewmodel/ViewModelFacetForViewModelInterface.java
@@ -19,7 +19,9 @@
 package org.apache.causeway.core.metamodel.facets.object.viewmodel;
 
 import java.lang.reflect.Constructor;
+import java.util.Map;
 import java.util.Optional;
+import java.util.stream.Collectors;
 
 import org.springframework.lang.Nullable;
 
@@ -28,6 +30,7 @@ import org.apache.causeway.applib.services.bookmark.Bookmark;
 import org.apache.causeway.applib.services.registry.ServiceRegistry;
 import org.apache.causeway.commons.collections.Can;
 import org.apache.causeway.commons.functional.IndexedConsumer;
+import org.apache.causeway.commons.internal.assertions._Assert;
 import org.apache.causeway.core.config.progmodel.ProgrammingModelConstants;
 import org.apache.causeway.core.metamodel.commons.ClassExtensions;
 import org.apache.causeway.core.metamodel.facetapi.FacetHolder;
@@ -47,8 +50,8 @@ import lombok.val;
 public class ViewModelFacetForViewModelInterface
 extends ViewModelFacetAbstract {
 
-    public static Optional<ViewModelFacet> create(
-            final Class<?> cls,
+    public static <T> Optional<ViewModelFacet> create(
+            final Class<T> cls,
             final FacetHolder holder,
             final HasPostConstructMethodCache postConstructMethodCache) {
 
@@ -56,23 +59,69 @@ extends ViewModelFacetAbstract {
             return Optional.empty();
         }
 
+        Constructor<?> pickedConstructor = null; // not used for abstract types
+
         if(!cls.isInterface()
-                && !ClassExtensions.isAbstract(cls)
-                && 
!ProgrammingModelConstants.ViewmodelConstructor.PUBLIC_ANY_ARGS.get(cls).isPresent())
 {
-            ValidationFailure.raiseFormatted(holder,
-                    
ProgrammingModelConstants.Validation.VIEWMODEL_MISSING_OR_MULTIPLE_PUBLIC_CONSTRUCTORS
-                        .getMessageForType(cls.getName()));
+                && !ClassExtensions.isAbstract(cls)) {
+
+            val explicitInjectConstructors = 
ProgrammingModelConstants.ViewmodelConstructor.PUBLIC_WITH_INJECT_SEMANTICS.getAll(cls);
+            val publicConstructors = 
ProgrammingModelConstants.ViewmodelConstructor.PUBLIC_ANY.getAll(cls);
+
+            if(explicitInjectConstructors.getCardinality().isMultiple()) {
+                if(!explicitInjectConstructors.getCardinality().isOne()) {
+                    ValidationFailure.raiseFormatted(holder,
+                            
ProgrammingModelConstants.Validation.VIEWMODEL_MULTIPLE_CONSTRUCTORS_WITH_INJECT_SEMANTICS
+                                .getMessage(Map.of(
+                                        "type", cls.getName(),
+                                        "found", 
explicitInjectConstructors.getCardinality().isMultiple()
+                                            ? "{" + 
explicitInjectConstructors.stream()
+                                                    .map(Constructor::toString)
+                                                    
.collect(Collectors.joining(", ")) + "}"
+                                            : "none")));
+
+                    return Optional.empty();
+                }
+            }
+
+            if(explicitInjectConstructors.getCardinality().isZero()) {
+
+                // in absence of a constructor with inject semantics there 
must be exactly one public to pick instead
+
+                if(!publicConstructors.getCardinality().isOne()) {
+                    ValidationFailure.raiseFormatted(holder,
+                            
ProgrammingModelConstants.Validation.VIEWMODEL_MISSING_OR_MULTIPLE_PUBLIC_CONSTRUCTORS
+                                .getMessage(Map.of(
+                                        "type", cls.getName(),
+                                        "found", 
publicConstructors.getCardinality().isMultiple()
+                                            ? "{" + publicConstructors.stream()
+                                                    .map(Constructor::toString)
+                                                    
.collect(Collectors.joining(", ")) + "}"
+                                            : "none")));
+
+                    return Optional.empty();
+                }
+
+            }
+
+            // -- else happy case
+
+            pickedConstructor = 
explicitInjectConstructors.getCardinality().isOne()
+                    ? explicitInjectConstructors.getSingletonOrFail()
+                    : publicConstructors.getSingletonOrFail();
 
-            return Optional.empty();
         }
 
-        return Optional.of(new ViewModelFacetForViewModelInterface(holder, 
postConstructMethodCache));
+        return Optional.of(new ViewModelFacetForViewModelInterface(holder, 
pickedConstructor, postConstructMethodCache));
     }
 
+    private Constructor<?> constructorAnyArgs;
+
     protected ViewModelFacetForViewModelInterface(
             final FacetHolder holder,
+            final @Nullable Constructor<?> constructorAnyArgs,
             final HasPostConstructMethodCache postConstructMethodCache) {
         super(holder, postConstructMethodCache,  Precedence.HIGH);
+        this.constructorAnyArgs = constructorAnyArgs;
     }
 
     @Override
@@ -107,9 +156,9 @@ extends ViewModelFacetAbstract {
     private Object deserialize(
             @NonNull final ObjectSpecification viewmodelSpec,
             @Nullable final String memento) {
-        val constructorAnyArgs = 
ProgrammingModelConstants.ViewmodelConstructor.PUBLIC_ANY_ARGS
-                .get(viewmodelSpec.getCorrespondingClass())
-                .orElseThrow();
+
+        _Assert.assertNotNull(constructorAnyArgs, ()->"framework bug: required 
non-null, "
+                + "this can only happen, if we try to deserialize an abstract 
type");
 
         val resolvedArgs = resolveArgsForConstructor(constructorAnyArgs, 
getServiceRegistry(), memento);
 
@@ -122,6 +171,7 @@ extends ViewModelFacetAbstract {
             final Constructor<?> constructor,
             final ServiceRegistry serviceRegistry,
             final String memento) {
+
         val params = Can.ofArray(constructor.getParameters());
         val args = new Object[params.size()];
         params.forEach(IndexedConsumer.zeroBased((i, param)->{
diff --git 
a/examples/demo/domain/src/main/java/demoapp/dom/domain/_interactions/InteractionDtoVm.java
 
b/examples/demo/domain/src/main/java/demoapp/dom/domain/_interactions/InteractionDtoVm.java
index 37f2962dc4..723ab3912d 100644
--- 
a/examples/demo/domain/src/main/java/demoapp/dom/domain/_interactions/InteractionDtoVm.java
+++ 
b/examples/demo/domain/src/main/java/demoapp/dom/domain/_interactions/InteractionDtoVm.java
@@ -21,6 +21,7 @@ package demoapp.dom.domain._interactions;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 
+import javax.inject.Inject;
 import javax.inject.Named;
 
 import org.apache.causeway.applib.ViewModel;
@@ -73,6 +74,7 @@ public class InteractionDtoVm implements ViewModel {
 
     // -- VIEWMODEL CONTRACT
 
+    @Inject
     public InteractionDtoVm(final String memento) {
         interactionDto = 
InteractionDtoUtils.fromXml(encodingService.decodeToString(memento));
     }
diff --git 
a/extensions/security/secman/applib/src/main/java/org/apache/causeway/extensions/secman/applib/feature/api/ApplicationFeatureChoices.java
 
b/extensions/security/secman/applib/src/main/java/org/apache/causeway/extensions/secman/applib/feature/api/ApplicationFeatureChoices.java
index 576d4c80c1..68d2a5164f 100644
--- 
a/extensions/security/secman/applib/src/main/java/org/apache/causeway/extensions/secman/applib/feature/api/ApplicationFeatureChoices.java
+++ 
b/extensions/security/secman/applib/src/main/java/org/apache/causeway/extensions/secman/applib/feature/api/ApplicationFeatureChoices.java
@@ -160,6 +160,7 @@ public class ApplicationFeatureChoices {
 
         // -- VIEWMODEL CONTRACT
 
+        @Inject
         public AppFeat(final String memento) {
             this(ApplicationFeatureId.parseEncoded(memento)); // fail by 
intention if memento is '<no id>'
         }
diff --git 
a/extensions/security/secman/applib/src/main/java/org/apache/causeway/extensions/secman/applib/user/dom/mixins/perms/UserPermissionViewModel.java
 
b/extensions/security/secman/applib/src/main/java/org/apache/causeway/extensions/secman/applib/user/dom/mixins/perms/UserPermissionViewModel.java
index 04f15d749b..be90c216e0 100644
--- 
a/extensions/security/secman/applib/src/main/java/org/apache/causeway/extensions/secman/applib/user/dom/mixins/perms/UserPermissionViewModel.java
+++ 
b/extensions/security/secman/applib/src/main/java/org/apache/causeway/extensions/secman/applib/user/dom/mixins/perms/UserPermissionViewModel.java
@@ -116,6 +116,7 @@ public class UserPermissionViewModel implements ViewModel {
 
     // -- VIEWMODEL CONTRACT
 
+    @Inject
     public UserPermissionViewModel(final String memento) {
         val payload = _Serializables.read(String[].class,
                 
_Bytes.ofUrlBase64.apply(memento.getBytes(StandardCharsets.US_ASCII)));

Reply via email to