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 5b996b7bbb ISIS-3293: resolve arbitrary args for ViewModel construction
5b996b7bbb is described below

commit 5b996b7bbb91740434c198895faca2e63afa67c7
Author: Andi Huber <[email protected]>
AuthorDate: Thu Nov 24 14:39:08 2022 +0100

    ISIS-3293: resolve arbitrary args for ViewModel construction
---
 .../appfeatui/ApplicationFeatureViewModel.java     |  2 +-
 .../services/appfeatui/ApplicationNamespace.java   | 13 ++--
 .../applib/services/appfeatui/ApplicationType.java | 16 +++--
 .../services/appfeatui/ApplicationTypeAction.java  | 14 +++--
 .../appfeatui/ApplicationTypeCollection.java       | 14 +++--
 .../services/appfeatui/ApplicationTypeMember.java  | 14 ++---
 .../appfeatui/ApplicationTypeProperty.java         | 15 ++---
 .../commons/internal/reflection/_ClassCache.java   |  6 ++
 .../progmodel/ProgrammingModelConstants.java       | 16 ++---
 .../ViewModelSemanticCheckingFacetFactory.java     | 22 ++++---
 .../ViewModelFacetForViewModelInterface.java       | 37 +++++++++---
 .../testdomain/factory/ViewModelFactoryTest.java   | 70 ++++++++++++++++------
 12 files changed, 158 insertions(+), 81 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 ed37d3dd7e..ffe4f9d99c 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(new 
ApplicationNamespace(featureId));
+            return 
factoryService.viewModel(ApplicationNamespace.of(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 1cdc23a0a7..54d4820fb3 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
@@ -48,16 +48,19 @@ public class ApplicationNamespace extends 
ApplicationFeatureViewModel {
 
     public static abstract class CollectionDomainEvent<T> extends 
ApplicationFeatureViewModel.CollectionDomainEvent<ApplicationNamespace, T> {}
 
-    // -- CONSTRUCTORS
+    // -- CONSTRUCTION
 
-    public ApplicationNamespace() { }
-    public ApplicationNamespace(final ApplicationFeatureId featureId) {
-        super(featureId);
-    }
     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 7b8360f8db..121774c658 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
@@ -51,19 +51,17 @@ 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);
-    }
     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 c0c132aa37..028884df2f 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
@@ -47,15 +47,17 @@ public class ApplicationTypeAction extends 
ApplicationTypeMember {
 
     public static abstract class PropertyDomainEvent<T> extends 
ApplicationTypeMember.PropertyDomainEvent<ApplicationTypeAction, T> {}
 
-    // -- constructors
-    public ApplicationTypeAction() { }
-    public ApplicationTypeAction(final ApplicationFeatureId featureId) {
-        super(featureId);
-    }
+    // -- CONSTRUCTION
+
     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 6380a6cfd8..db525c646f 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
@@ -45,15 +45,17 @@ public class ApplicationTypeCollection extends 
ApplicationTypeMember {
 
     public static abstract class PropertyDomainEvent<T> extends 
ApplicationTypeMember.PropertyDomainEvent<ApplicationTypeCollection, T> {}
 
-    // -- constructors
-    public ApplicationTypeCollection() {}
-    public ApplicationTypeCollection(final ApplicationFeatureId featureId) {
-        super(featureId);
-    }
+    // -- CONSTRUCTION
+
     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/ApplicationTypeMember.java
 
b/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationTypeMember.java
index ff03bfba34..91bd04953a 100644
--- 
a/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationTypeMember.java
+++ 
b/api/applib/src/main/java/org/apache/causeway/applib/services/appfeatui/ApplicationTypeMember.java
@@ -48,17 +48,17 @@ public abstract class ApplicationTypeMember extends 
ApplicationFeatureViewModel
 
     static final String LOGICAL_TYPE_NAME = 
CausewayModuleApplib.NAMESPACE_FEAT + ".ApplicationTypeMember";
 
-    public static abstract class PropertyDomainEvent<S extends 
ApplicationTypeMember, T> extends 
ApplicationFeatureViewModel.PropertyDomainEvent<ApplicationTypeMember, T> {}
+    public static abstract class PropertyDomainEvent<S extends 
ApplicationTypeMember, T>
+    extends 
ApplicationFeatureViewModel.PropertyDomainEvent<ApplicationTypeMember, T> {}
 
+    // -- CONSTRUCTION
 
-    // -- constructors
-    public ApplicationTypeMember(final ApplicationFeatureId featureId) {
-        super(featureId);
-    }
-    public ApplicationTypeMember(final String memento) {
+    protected ApplicationTypeMember(final String memento) {
         super(memento);
     }
-
+    protected ApplicationTypeMember(final ApplicationFeatureId featureId) {
+        super(featureId);
+    }
 
     // -- memberName (properties)
 
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 53a7d7c407..7fdcc2dde2 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
@@ -50,16 +50,17 @@ public class ApplicationTypeProperty extends 
ApplicationTypeMember {
 
     public static abstract class PropertyDomainEvent<T> extends 
ApplicationTypeMember.PropertyDomainEvent<ApplicationTypeProperty, T> {}
 
-    // -- constructors
-    public ApplicationTypeProperty() { }
-    public ApplicationTypeProperty(final ApplicationFeatureId featureId) {
-        super(featureId);
-    }
+    // -- CONSTRUCTION
+
     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/org/apache/causeway/commons/internal/reflection/_ClassCache.java
 
b/commons/src/main/java/org/apache/causeway/commons/internal/reflection/_ClassCache.java
index ee826c9297..5acc34abdf 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
@@ -32,6 +32,7 @@ import org.springframework.util.ReflectionUtils;
 
 import org.apache.causeway.commons.collections.Can;
 import org.apache.causeway.commons.internal._Constants;
+import org.apache.causeway.commons.internal.base._Casts;
 import org.apache.causeway.commons.internal.base._Strings;
 import org.apache.causeway.commons.internal.collections._Arrays;
 import org.apache.causeway.commons.internal.context._Context;
@@ -76,6 +77,11 @@ public final class _ClassCache implements AutoCloseable {
         inspectType(type);
     }
 
+    public <T> Can<Constructor<T>> getPublicConstructors(final Class<T> type) {
+        return Can.ofCollection(_Casts.uncheckedCast(
+                inspectType(type).publicConstructorsByKey.values()));
+    }
+
     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 dc7c1b9a52..8f30c8aa67 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
@@ -64,6 +64,7 @@ import 
org.apache.causeway.commons.internal.collections._Collections;
 import org.apache.causeway.commons.internal.collections._Lists;
 import org.apache.causeway.commons.internal.exceptions._Exceptions;
 import org.apache.causeway.commons.internal.reflection._Annotations;
+import org.apache.causeway.commons.internal.reflection._ClassCache;
 import org.apache.causeway.commons.internal.reflection._Reflect;
 
 import static 
org.apache.causeway.commons.internal.reflection._Reflect.Filter.paramAssignableFrom;
@@ -481,9 +482,9 @@ 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_MISSING_DESERIALIZING_CONSTRUCTOR(
-                "${type}: ViewModel contract violation: missing single 
(String) arg constructor "
-                + "(for de-serialization from memento string)."),
+        VIEWMODEL_MISSING_OR_MULTIPLE_PUBLIC_CONSTRUCTORS(
+                "${type}: ViewModel contract violation: there must be exactly 
one public constructor. "
+                + "See " + 
org.apache.causeway.applib.ViewModel.class.getName() + " java-doc for 
details."),
         VIEWMODEL_MISSING_SERIALIZATION_STRATEGY(
                 "${type}: Missing ViewModel serialization strategy 
encountered; "
                 + "for ViewModels one of those must be true: "
@@ -539,14 +540,15 @@ public final class ProgrammingModelConstants {
     }
 
     public static enum ViewmodelConstructor {
-        SINGLE_STRING_ARG {
+        PUBLIC_ANY_ARGS {
 
             @Override
             public <T> Optional<Constructor<T>> get(final Class<T> cls) {
-                // heap-pollution: only produces stack-traces when cls 
violates viewmodel contract,
-                // which is covered by mm validation
+                // violation of view-model contract should be covered by 
meta-model validation
                 return Try.call(()->
-                        cls.getDeclaredConstructor(new 
Class<?>[]{String.class}))
+                    _ClassCache.getInstance()
+                        .getPublicConstructors(cls)
+                        .getSingleton().orElse(null))
                         .getValue();
             }
 
diff --git 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/ViewModelSemanticCheckingFacetFactory.java
 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/ViewModelSemanticCheckingFacetFactory.java
index 6678264504..50e7a3a5dc 100644
--- 
a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/ViewModelSemanticCheckingFacetFactory.java
+++ 
b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/facets/object/ViewModelSemanticCheckingFacetFactory.java
@@ -41,22 +41,28 @@ extends FacetFactoryAbstract {
     @Override
     public void process(final ProcessClassContext processClassContext) {
 
-        // disable by default
-        final boolean enable = 
getConfiguration().getApplib().getAnnotation().getViewModel().getValidation().getSemanticChecking().isEnable();
-        if(!enable) {
+        val cls = processClassContext.getCls();
+
+        final boolean implementsViewModel = 
org.apache.causeway.applib.ViewModel.class.isAssignableFrom(cls);
+        if(!implementsViewModel){
             return;
         }
 
+        
if(getConfiguration().getApplib().getAnnotation().getViewModel().getValidation().getSemanticChecking().isEnable())
 {
+            checkViewModelSemantics(processClassContext);
+        }
+    }
+
+    // -- HELPER
+
+    private void checkViewModelSemantics(final ProcessClassContext 
processClassContext) {
         val cls = processClassContext.getCls();
         val facetHolder = processClassContext.getFacetHolder();
 
         final DomainObject domainObject = 
processClassContext.synthesizeOnType(DomainObject.class).orElse(null);
-        final boolean implementsViewModel = 
org.apache.causeway.applib.ViewModel.class.isAssignableFrom(cls);
-
         final boolean annotatedWithDomainObject = domainObject != null;
 
-        if(implementsViewModel
-                && annotatedWithDomainObject
+        if(annotatedWithDomainObject
                 && (domainObject.nature().isBean()
                         || domainObject.nature().isEntity())) {
             ValidationFailure.raise(
@@ -70,8 +76,6 @@ extends FacetFactoryAbstract {
                         DomainObject.class.getSimpleName())
                     );
         }
-
     }
 
-
 }
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 55d2a2364c..32af74c142 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
@@ -18,13 +18,18 @@
  */
 package org.apache.causeway.core.metamodel.facets.object.viewmodel;
 
+import java.lang.reflect.Constructor;
 import java.util.Optional;
 
 import org.springframework.lang.Nullable;
 
 import org.apache.causeway.applib.ViewModel;
 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.core.config.progmodel.ProgrammingModelConstants;
+import org.apache.causeway.core.metamodel.commons.ClassExtensions;
 import org.apache.causeway.core.metamodel.facetapi.FacetHolder;
 import org.apache.causeway.core.metamodel.facets.HasPostConstructMethodCache;
 import org.apache.causeway.core.metamodel.object.ManagedObject;
@@ -51,12 +56,11 @@ extends ViewModelFacetAbstract {
             return Optional.empty();
         }
 
-        if(!ProgrammingModelConstants.ViewmodelConstructor.SINGLE_STRING_ARG
-            .get(cls)
-            .isPresent()) {
-
+        if(!cls.isInterface()
+                && !ClassExtensions.isAbstract(cls)
+                && 
!ProgrammingModelConstants.ViewmodelConstructor.PUBLIC_ANY_ARGS.get(cls).isPresent())
 {
             ValidationFailure.raiseFormatted(holder,
-                    
ProgrammingModelConstants.Validation.VIEWMODEL_MISSING_DESERIALIZING_CONSTRUCTOR
+                    
ProgrammingModelConstants.Validation.VIEWMODEL_MISSING_OR_MULTIPLE_PUBLIC_CONSTRUCTORS
                         .getMessageForType(cls.getName()));
 
             return Optional.empty();
@@ -103,12 +107,31 @@ extends ViewModelFacetAbstract {
     private Object deserialize(
             @NonNull final ObjectSpecification viewmodelSpec,
             @Nullable final String memento) {
-        val constructorTakingMemento = 
ProgrammingModelConstants.ViewmodelConstructor.SINGLE_STRING_ARG
+        val constructorAnyArgs = 
ProgrammingModelConstants.ViewmodelConstructor.PUBLIC_ANY_ARGS
                 .get(viewmodelSpec.getCorrespondingClass())
                 .orElseThrow();
+
+        val resolvedArgs = resolveArgsForConstructor(constructorAnyArgs, 
getServiceRegistry(), memento);
+
         val viewmodelPojo = _Privileged
-                .newInstance(constructorTakingMemento, memento);
+                .newInstance(constructorAnyArgs, resolvedArgs);
         return viewmodelPojo;
     }
 
+    private static Object[] resolveArgsForConstructor(
+            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)->{
+            if(param.getType().equals(String.class)) {
+                args[i] = memento; // its ok to do this never, once, or more 
than once per constructor, see ViewModel java-doc
+                return;
+            }
+            args[i] = serviceRegistry.lookupServiceElseFail(param.getType());
+        }));
+        return args;
+    }
+
 }
diff --git 
a/regressiontests/stable-factory/src/test/java/org/apache/causeway/testdomain/factory/ViewModelFactoryTest.java
 
b/regressiontests/stable-factory/src/test/java/org/apache/causeway/testdomain/factory/ViewModelFactoryTest.java
index 5dd7b7fb4d..42fa0fc29c 100644
--- 
a/regressiontests/stable-factory/src/test/java/org/apache/causeway/testdomain/factory/ViewModelFactoryTest.java
+++ 
b/regressiontests/stable-factory/src/test/java/org/apache/causeway/testdomain/factory/ViewModelFactoryTest.java
@@ -25,10 +25,14 @@ import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.test.context.TestPropertySource;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
+import org.apache.causeway.applib.ViewModel;
 import org.apache.causeway.applib.annotation.DomainObject;
 import org.apache.causeway.applib.annotation.Nature;
+import org.apache.causeway.applib.services.bookmark.Bookmark;
+import org.apache.causeway.applib.services.registry.ServiceRegistry;
 import org.apache.causeway.applib.services.repository.RepositoryService;
 import org.apache.causeway.core.config.presets.CausewayPresets;
 import org.apache.causeway.testdomain.conf.Configuration_headless;
@@ -39,7 +43,7 @@ import lombok.RequiredArgsConstructor;
 import lombok.val;
 
 @SpringBootTest(
-        classes = { 
+        classes = {
                 Configuration_headless.class,
         }
 )
@@ -47,11 +51,11 @@ import lombok.val;
 class ViewModelFactoryTest extends CausewayIntegrationTestAbstract {
 
     // -- VIEW MODEL SAMPLES
-    
+
     @DomainObject(nature = Nature.VIEW_MODEL)
     public static class SimpleViewModel {
         @Inject private RepositoryService repository;
-        
+
         public boolean areInjectionPointsResolved() {
             return repository!=null;
         }
@@ -59,32 +63,64 @@ class ViewModelFactoryTest extends 
CausewayIntegrationTestAbstract {
 
     @DomainObject(nature = Nature.VIEW_MODEL)
     @RequiredArgsConstructor
-    public static class AdvancedViewModel {
+    public static class ViewModelWithInjectableFields implements ViewModel {
 
         @Inject private RepositoryService repository;
         @Getter private final String name;
-        
-        public boolean areInjectionPointsResolved() {
-            return repository!=null;
+
+        public void assertInitialized() {
+            assertNotNull(repository, ()->"repository (field) not injected");
+            assertEquals("aName", getName(), ()->"unexpected name (constructor 
arg)");
+        }
+
+        @Override
+        public String viewModelMemento() {
+            return "aName";
+        }
+    }
+
+
+    @DomainObject(nature = Nature.VIEW_MODEL)
+    @RequiredArgsConstructor
+    public static class ViewModelWithInjectableConstructorArgs implements 
ViewModel {
+
+        @Inject private RepositoryService repository;
+        private final ServiceRegistry registry;
+        @Getter private final String name;
+
+        public void assertInitialized() {
+            assertNotNull(repository, ()->"repository (field) not injected");
+            assertNotNull(registry, ()->"registry (constructor arg) not 
injected");
+            assertEquals("aName", getName(), ()->"unexpected name (constructor 
arg)");
+        }
+
+        @Override
+        public String viewModelMemento() {
+            return "aName";
         }
     }
-    
+
     // -- TESTS
-    
+
     @Test
     void sampleViewModel_shouldHave_injectionPointsResolved() {
         val sampleViewModel = factoryService.viewModel(SimpleViewModel.class);
-
         assertTrue(sampleViewModel.areInjectionPointsResolved());
     }
-    
+
+    @Test
+    void viewModel_shouldHave_injectionPointsResolved() {
+        val viewModel = factoryService.viewModel(new 
ViewModelWithInjectableFields("aName"));
+        viewModel.assertInitialized();
+    }
+
     @Test
-    void advancedViewModel_shouldHave_injectionPointsResolved() {
-        val advancedViewModel = factoryService.viewModel(new 
AdvancedViewModel("aName"));
-        
-        assertTrue(advancedViewModel.areInjectionPointsResolved());
-        assertEquals("aName", advancedViewModel.getName());
+    void viewModel_shouldHave_constructorArgsResolved() {
+        ViewModelWithInjectableConstructorArgs viewModel = 
factoryService.viewModel(ViewModelWithInjectableConstructorArgs.class,
+                Bookmark.forLogicalTypeNameAndIdentifier(
+                        ViewModelWithInjectableConstructorArgs.class.getName(),
+                        "aName"));
+        viewModel.assertInitialized();
     }
 
-    
 }

Reply via email to