You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2020/05/02 10:30:45 UTC

[isis] branch master updated: ISIS-2340: tackle the ScalarModel monster

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 20e121f  ISIS-2340: tackle the ScalarModel monster
20e121f is described below

commit 20e121f9e1816a970fdae31971d6db2ccb076ec5
Author: Andi Huber <ah...@apache.org>
AuthorDate: Sat May 2 12:30:32 2020 +0200

    ISIS-2340: tackle the ScalarModel monster
---
 .../core/metamodel/commons/ClassExtensions.java    |   8 +
 .../ActionParameterDefaultsFacetViaMethod.java     |  20 +-
 .../isis/core/metamodel/spec/ManagedObject.java    |  21 +-
 .../core/metamodel/spec/feature/ObjectAction.java  |  13 +-
 .../spec/feature/ObjectActionParameter.java        |   7 +-
 .../specloader/specimpl/ObjectActionDefault.java   |  11 +-
 .../specloader/specimpl/ObjectActionMixedIn.java   |   6 +-
 .../specloader/specimpl/PendingParameterModel.java | 107 +--
 ...erModel.java => PendingParameterModelHead.java} |  65 +-
 .../pdfjs/ui/components/PdfJsViewerPanel.java      |   3 +-
 .../domainobjects/ObjectActionReprRenderer.java    |   4 +-
 .../viewer/wicket/model/models/ActionModel.java    |   9 +-
 .../viewer/wicket/model/models/EntityModel.java    |   2 +-
 .../viewer/wicket/model/models/ScalarModel.java    | 866 ++-------------------
 .../wicket/model/models/ScalarParameterModel.java  | 328 ++++++++
 .../wicket/model/models/ScalarPropertyModel.java   | 378 +++++++++
 .../ScalarModel_isScalarSubtypingAnyOf_Test.java   |   2 +-
 .../components/actions/ActionParametersForm.java   |   5 +-
 .../ui/components/property/PropertyEditForm.java   |  19 +-
 .../components/property/PropertyEditFormPanel.java |   8 +-
 .../property/PropertyEditFormPanelFactory.java     |   6 +-
 .../ui/components/property/PropertyEditPanel.java  |   9 +-
 .../property/PropertyEditPanelFactory.java         |   6 +-
 .../property/PropertyFormExecutorStrategy.java     |  10 +-
 .../PropertyEditPromptHeaderPanel.java             |   6 +-
 .../ui/components/scalars/ScalarPanelAbstract.java |   4 +-
 .../components/scalars/ScalarPanelAbstract2.java   |  36 +-
 .../scalars/ScalarPanelSelect2Abstract.java        |   6 +-
 28 files changed, 949 insertions(+), 1016 deletions(-)

diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/commons/ClassExtensions.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/commons/ClassExtensions.java
index d586240..7129044 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/commons/ClassExtensions.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/commons/ClassExtensions.java
@@ -24,6 +24,7 @@ import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.net.URL;
+import java.util.Objects;
 
 import org.apache.isis.core.commons.exceptions.IsisException;
 import org.apache.isis.core.commons.internal._Constants;
@@ -177,4 +178,11 @@ public final class ClassExtensions {
         return (returnTypeExtendee.isAssignableFrom(type));
     }
 
+    public static boolean equalsWhenBoxing(Class<?> t1, Class<?> t2) {
+        if(Objects.equals(t1, t2)) {
+            return true;
+        }
+        return Objects.equals(asWrappedIfNecessary(t1), asWrappedIfNecessary(t2));
+    }
+
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/defaults/methodnum/ActionParameterDefaultsFacetViaMethod.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/defaults/methodnum/ActionParameterDefaultsFacetViaMethod.java
index 13e9665..da36b91 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/defaults/methodnum/ActionParameterDefaultsFacetViaMethod.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/param/defaults/methodnum/ActionParameterDefaultsFacetViaMethod.java
@@ -76,7 +76,7 @@ public class ActionParameterDefaultsFacetViaMethod extends ActionParameterDefaul
     @Override
     public Object getDefault(@NonNull PendingParameterModel pendingArgs) {
 
-        if(pendingArgs.isPopulated()) {
+//        if(pendingArgs.isPopulated()) {
             
             // call with args: defaultNAct(X x, Y y, ...) 
             
@@ -91,18 +91,18 @@ public class ActionParameterDefaultsFacetViaMethod extends ActionParameterDefaul
             return ManagedObject.InvokeUtil
                     .invokeAutofit(method, 
                         pendingArgs.getActionTarget(), pendingArgs.getParamValues());
-        }
+//        }
         
         // call no-arg defaultNAct() instead
         
-        if(ppmFactory.isPresent()) {
-            // PPM programming model
-            return ManagedObject.InvokeUtil
-                    .invokeWithPPM(ppmFactory.get(), method, 
-                            pendingArgs.getActionTarget(), pendingArgs.getEmptyValues());    
-        }
-        
-        return ManagedObject.InvokeUtil.invoke(method, pendingArgs.getActionTarget());
+//        if(ppmFactory.isPresent()) {
+//            // PPM programming model
+//            return ManagedObject.InvokeUtil
+//                    .invokeWithPPM(ppmFactory.get(), method, 
+//                            pendingArgs.getActionTarget(), pendingArgs.getEmptyValues());    
+//        }
+//        
+//        return ManagedObject.InvokeUtil.invoke(method, pendingArgs.getActionTarget());
         
 // legacy of        
 //        // this isn't a dependent defaults situation, so just evaluate the default.
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObject.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObject.java
index b0a563b..7e5853c 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObject.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObject.java
@@ -352,13 +352,20 @@ public interface ManagedObject {
      */
     public static ManagedObject of(ObjectSpecification specification, Object pojo) {
         // can do this check only when the pojo is not null, otherwise is always considered valid
-        if(pojo!=null && !specification.getCorrespondingClass().isAssignableFrom(pojo.getClass())) {
-            throw _Exceptions.illegalArgument(
-                    "Pojo not compatible with ObjectSpecification, " +
-                    "objectSpec.correspondingClass = %s, " +
-                    "pojo.getClass() = %s, " +
-                    "pojo.toString() = %s",
-                    specification.getCorrespondingClass(), pojo.getClass(), pojo.toString());
+        if(pojo!=null) {
+            val expectedType = specification.getCorrespondingClass();
+            val actualType = pojo.getClass();
+            
+            if(!expectedType.isAssignableFrom(actualType)) {
+                if(!ClassExtensions.equalsWhenBoxing(expectedType, actualType)) {
+                    throw _Exceptions.illegalArgument(
+                            "Pojo not compatible with ObjectSpecification, " +
+                            "objectSpec.correspondingClass = %s, " +
+                            "pojo.getClass() = %s, " +
+                            "pojo.toString() = %s",
+                            specification.getCorrespondingClass(), pojo.getClass(), pojo.toString());    
+                }
+            }    
         }
         return new SimpleManagedObject(specification, pojo);
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
index 8ad07d5..c7a70e1 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectAction.java
@@ -55,7 +55,7 @@ import org.apache.isis.core.metamodel.spec.ActionType;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.specloader.specimpl.MixedInMember;
-import org.apache.isis.core.metamodel.specloader.specimpl.PendingParameterModel;
+import org.apache.isis.core.metamodel.specloader.specimpl.PendingParameterModelHead;
 
 import static org.apache.isis.core.commons.internal.base._NullSafe.stream;
 
@@ -160,16 +160,9 @@ public interface ObjectAction extends ObjectMember {
 
 
     // -- Model for Parameter Negotiation
-    
-    
-    PendingParameterModel newPendingParameterModel(
-            @NonNull ManagedObject actionOwner,
-            @NonNull Can<ManagedObject> paramValues);
 
-    default PendingParameterModel newPendingParameterModel(
-            @NonNull ManagedObject actionOwner) {
-        return newPendingParameterModel(actionOwner, Can.empty()); // init defaults
-    }
+    PendingParameterModelHead newPendingParameterModelHead(
+            @NonNull ManagedObject actionOwner);
     
     // -- Parameters (declarative)
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectActionParameter.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectActionParameter.java
index 2c08556..921b72d 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectActionParameter.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectActionParameter.java
@@ -113,11 +113,14 @@ public interface ObjectActionParameter extends ObjectFeature, CurrentHolder {
             PendingParameterModel pendingArgs,
             InteractionInitiatedBy interactionInitiatedBy);
 
-
     ManagedObject getDefault(PendingParameterModel pendingArgs);
 
+    /** default value as result of a initial param value fixed point search */
     default ManagedObject getDefault(ManagedObject actionOnwer) {
-        return getDefault(getAction().newPendingParameterModel(actionOnwer));
+        return getAction()
+                .newPendingParameterModelHead(actionOnwer).defaults()
+                .getParamValues()
+                .getElseFail(getNumber());
     }
     
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionDefault.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionDefault.java
index ffc38eb..3648295 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionDefault.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionDefault.java
@@ -147,12 +147,9 @@ public class ObjectActionDefault extends ObjectMemberAbstract implements ObjectA
         return ActionType.USER;
     }
 
-
     @Override
-    public PendingParameterModel newPendingParameterModel(
-            @NonNull ManagedObject actionOwner,
-            @NonNull Can<ManagedObject> paramValues) {
-        return PendingParameterModel.of(this, actionOwner, actionOwner, paramValues);
+    public PendingParameterModelHead newPendingParameterModelHead(@NonNull ManagedObject actionOwner) {
+        return PendingParameterModelHead.of(this, actionOwner, actionOwner);
     }
     
     // -- Parameters
@@ -479,8 +476,8 @@ public class ObjectActionDefault extends ObjectMemberAbstract implements ObjectA
         
         // else use the new defaultNXxx approach for each param in turn
         // (the reflector will have made sure both aren't installed).
-        return newPendingParameterModel(target, Can.empty())
-                .defaultsFixedPointSearch()
+        return newPendingParameterModelHead(target)
+                .defaults()
                 .getParamValues();
 
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
index 4354c1a..1396c07 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java
@@ -137,10 +137,8 @@ public class ObjectActionMixedIn extends ObjectActionDefault implements MixedInM
     }
 
     @Override
-    public PendingParameterModel newPendingParameterModel(
-            @NonNull ManagedObject actionOwner,
-            @NonNull Can<ManagedObject> paramValues) {
-        return PendingParameterModel.of(this, actionOwner, mixinAdapterFor(actionOwner), paramValues);
+    public PendingParameterModelHead newPendingParameterModelHead(@NonNull ManagedObject actionOwner) {
+        return PendingParameterModelHead.of(this, actionOwner, mixinAdapterFor(actionOwner));
     }
     
     @Override
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/PendingParameterModel.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/PendingParameterModel.java
index 20fba1e..b0ed019 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/PendingParameterModel.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/PendingParameterModel.java
@@ -18,24 +18,15 @@
  */
 package org.apache.isis.core.metamodel.specloader.specimpl;
 
-import java.util.Objects;
-import java.util.function.Function;
-
 import org.apache.isis.core.commons.collections.Can;
-import org.apache.isis.core.commons.internal.assertions._Assert;
-import org.apache.isis.core.commons.internal.exceptions._Exceptions;
-import org.apache.isis.core.metamodel.facets.param.defaults.ActionParameterDefaultsFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.core.metamodel.spec.ObjectSpecification;
-import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 
 import lombok.Getter;
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
-import lombok.val;
 
 /**
- * Model used to negotiate the paramValues of an action by means of a UI dialog.
+ * Model used to negotiate the paramValues of an action by means of an UI dialog.
  *  
  * @since 2.0.0
  */
@@ -43,103 +34,15 @@ import lombok.val;
 @RequiredArgsConstructor(staticName = "of")
 public class PendingParameterModel {
 
-    @NonNull private final ObjectAction action;
-    @NonNull private final ManagedObject actionOwner;
-    
-    /** 
-     * typically equal to {@code actionOwner}, except for mixins, where {@code actionTarget}
-     * is the mixin instance 
-     */
-    @NonNull private final ManagedObject actionTarget; 
-    
-    /**
-     * Has special meaning when empty, that is, this instance is only used
-     * to initialize phase 1 in step 1 of 'Fill in defaults' see
-     * <a href="https://cwiki.apache.org/confluence/display/ISIS/ActionParameterNegotiation">
-     * ActionParameterNegotiation (wiki)
-     * </a> 
-     */
+    @NonNull private final PendingParameterModelHead head;
     @NonNull private final Can<ManagedObject> paramValues;
-    
-    public final boolean isPopulated() {
-        return !paramValues.isEmpty();
-    }
-    
-    public Can<ManagedObject> getEmptyValues() {
-        return getAction().getParameters().stream()
-        .map(objectActionParameter->
-            ManagedObject.empty(objectActionParameter.getSpecification()))
-        .collect(Can.toCan());
-    }
-
-    public PendingParameterModel defaultsFixedPointSearch() {
-        
-        _Assert.assertTrue(isPopulated()); // don't start this algorithm with a populated model 
-        
-        final int maxIterations = getAction().getParameterCount();
-        val paramDefaultProviders = getParameterDefaultProviders();
-        
-        val initialDefaults = paramDefaultProviders
-        .map(paramDefaultProvider->paramDefaultProvider.getDefault(this));
-        
-        // fixed point search
-        
-        Can<ManagedObject> old_pl, pl = initialDefaults;
-        for(int i=0; i<maxIterations; ++i) {
-            val ppm = PendingParameterModel.of(action, actionOwner, actionTarget, pl);
-            old_pl = pl;
-            pl = paramDefaultProviders
-                    .map(paramDefaultProvider->paramDefaultProvider.getDefault(ppm));
-            
-            if(equals(old_pl, pl)) {
-                // fixed point found, return the latest iteration 
-                return PendingParameterModel.of(action, actionOwner, actionTarget, pl);
-            }
-            
-        }
-        
-        throw _Exceptions.unrecoverableFormatted("Cannot find an initial fixed point for action "
-                + "parameter defaults on action %s.", getAction());
-        
-    }
 
-    // -- HELPER
+    // -- SHORTCUTS
     
-    @RequiredArgsConstructor(staticName = "of")
-    private static final class ParameterDefaultProvider {
-        
-        final ObjectSpecification paramSpec;
-        final Function<PendingParameterModel, Object> defaultPojoProvider;
-        
-        ManagedObject getDefault(PendingParameterModel ppm) {
-            return ManagedObject.of(paramSpec, defaultPojoProvider.apply(ppm));
-        }
+    public ManagedObject getActionTarget() {
+        return getHead().getActionTarget();
     }
     
-    private Can<ParameterDefaultProvider> getParameterDefaultProviders() {
-        return getAction().getParameters().stream()
-        .map(objectActionParameter->{
-            val paramSpec = objectActionParameter.getSpecification();
-            val paramDefaultFacet = objectActionParameter.getFacet(ActionParameterDefaultsFacet.class);
-            return (paramDefaultFacet != null && !paramDefaultFacet.isFallback()) 
-                        ? ParameterDefaultProvider.of(paramSpec, ppm->paramDefaultFacet.getDefault(ppm))
-                        : ParameterDefaultProvider.of(paramSpec, ppm->null);
-        })
-        .collect(Can.toCan());
-    }
-    
-    private boolean equals(Can<ManagedObject> left, Can<ManagedObject> right) {
-        // equal length is guaranteed as used only local to this class
-        val leftIt = left.iterator();
-        for(val r : right) {
-            val leftPojo = leftIt.next().getPojo();
-            val rightPojo = r.getPojo();
-            if(!Objects.equals(leftPojo, rightPojo)){
-                return false;        
-            }
-        }
-        return true;
-    }
 
 
 
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/PendingParameterModel.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/PendingParameterModelHead.java
similarity index 77%
copy from core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/PendingParameterModel.java
copy to core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/PendingParameterModelHead.java
index 20fba1e..e1a50eb 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/PendingParameterModel.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/PendingParameterModelHead.java
@@ -22,7 +22,6 @@ import java.util.Objects;
 import java.util.function.Function;
 
 import org.apache.isis.core.commons.collections.Can;
-import org.apache.isis.core.commons.internal.assertions._Assert;
 import org.apache.isis.core.commons.internal.exceptions._Exceptions;
 import org.apache.isis.core.metamodel.facets.param.defaults.ActionParameterDefaultsFacet;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
@@ -35,65 +34,74 @@ import lombok.RequiredArgsConstructor;
 import lombok.val;
 
 /**
- * Model used to negotiate the paramValues of an action by means of a UI dialog.
+ * The 'head' of the a {@link PendingParameterModel}, that is it holds no parameter values.
  *  
  * @since 2.0.0
  */
 @Getter 
 @RequiredArgsConstructor(staticName = "of")
-public class PendingParameterModel {
+public class PendingParameterModelHead {
 
     @NonNull private final ObjectAction action;
     @NonNull private final ManagedObject actionOwner;
     
     /** 
-     * typically equal to {@code actionOwner}, except for mixins, where {@code actionTarget}
-     * is the mixin instance 
+     * typically equal to {@code actionOwner}, except for mixins, 
+     * where {@code actionTarget} is the mixin instance 
      */
     @NonNull private final ManagedObject actionTarget; 
     
-    /**
-     * Has special meaning when empty, that is, this instance is only used
-     * to initialize phase 1 in step 1 of 'Fill in defaults' see
-     * <a href="https://cwiki.apache.org/confluence/display/ISIS/ActionParameterNegotiation">
-     * ActionParameterNegotiation (wiki)
-     * </a> 
+    /**  
+     * Immutable tuple of ManagedObjects, each representing {@code null} and each holding 
+     * the corresponding parameter's {@code ObjectSpecification}.
+     * <p>
+     * The size of the tuple corresponds to the number of parameters.
      */
-    @NonNull private final Can<ManagedObject> paramValues;
-    
-    public final boolean isPopulated() {
-        return !paramValues.isEmpty();
-    }
-    
-    public Can<ManagedObject> getEmptyValues() {
+    public Can<ManagedObject> getEmptyParameterValues() {
         return getAction().getParameters().stream()
         .map(objectActionParameter->
             ManagedObject.empty(objectActionParameter.getSpecification()))
         .collect(Can.toCan());
     }
-
-    public PendingParameterModel defaultsFixedPointSearch() {
-        
-        _Assert.assertTrue(isPopulated()); // don't start this algorithm with a populated model 
+    
+    public PendingParameterModel model(
+            @NonNull Can<ManagedObject> paramValues) {
+        return PendingParameterModel.of(this, paramValues);
+    }
+    
+    public PendingParameterModel emptyModel() {
+        return PendingParameterModel.of(this, getEmptyParameterValues());
+    }
+    
+    /**
+     * See step 1 'Fill in defaults' in
+     * <a href="https://cwiki.apache.org/confluence/display/ISIS/ActionParameterNegotiation">
+     * ActionParameterNegotiation (wiki)
+     * </a> 
+     */
+    public PendingParameterModel defaults() {
         
         final int maxIterations = getAction().getParameterCount();
         val paramDefaultProviders = getParameterDefaultProviders();
         
+        // init defaults with empty pending-parameter values 
+        val emptyModel = emptyModel();
         val initialDefaults = paramDefaultProviders
-        .map(paramDefaultProvider->paramDefaultProvider.getDefault(this));
+        .map(paramDefaultProvider->paramDefaultProvider
+                .getDefault(emptyModel));
         
         // fixed point search
         
         Can<ManagedObject> old_pl, pl = initialDefaults;
         for(int i=0; i<maxIterations; ++i) {
-            val ppm = PendingParameterModel.of(action, actionOwner, actionTarget, pl);
+            val ppm = model(pl);
             old_pl = pl;
             pl = paramDefaultProviders
                     .map(paramDefaultProvider->paramDefaultProvider.getDefault(ppm));
             
             if(equals(old_pl, pl)) {
                 // fixed point found, return the latest iteration 
-                return PendingParameterModel.of(action, actionOwner, actionTarget, pl);
+                return model(pl);
             }
             
         }
@@ -112,7 +120,8 @@ public class PendingParameterModel {
         final Function<PendingParameterModel, Object> defaultPojoProvider;
         
         ManagedObject getDefault(PendingParameterModel ppm) {
-            return ManagedObject.of(paramSpec, defaultPojoProvider.apply(ppm));
+            val paramValuePojo = defaultPojoProvider.apply(ppm);
+            return ManagedObject.of(paramSpec, paramValuePojo);
         }
     }
     
@@ -141,7 +150,9 @@ public class PendingParameterModel {
         return true;
     }
 
+   
 
-
+    
+    
     
 }
diff --git a/extensions/vw/pdfjs/ui/src/main/java/org/apache/isis/extensions/viewer/wicket/pdfjs/ui/components/PdfJsViewerPanel.java b/extensions/vw/pdfjs/ui/src/main/java/org/apache/isis/extensions/viewer/wicket/pdfjs/ui/components/PdfJsViewerPanel.java
index 8e697d8..cc67420 100644
--- a/extensions/vw/pdfjs/ui/src/main/java/org/apache/isis/extensions/viewer/wicket/pdfjs/ui/components/PdfJsViewerPanel.java
+++ b/extensions/vw/pdfjs/ui/src/main/java/org/apache/isis/extensions/viewer/wicket/pdfjs/ui/components/PdfJsViewerPanel.java
@@ -57,6 +57,7 @@ import org.apache.isis.extensions.viewer.wicket.pdfjs.applib.config.Scale;
 import org.apache.isis.extensions.viewer.wicket.pdfjs.applib.spi.PdfJsViewerAdvisor;
 import org.apache.isis.extensions.viewer.wicket.pdfjs.metamodel.facet.PdfJsViewerFacet;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.model.models.ScalarPropertyModel;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelAbstract;
 
 import lombok.val;
@@ -66,7 +67,7 @@ import de.agilecoders.wicket.core.markup.html.bootstrap.common.NotificationPanel
 /**
  *
  */
-class PdfJsViewerPanel extends ScalarPanelAbstract implements IRequestListener {
+class PdfJsViewerPanel extends ScalarPanelAbstract<ScalarPropertyModel> implements IRequestListener {
 
     private static final long serialVersionUID = 1L;
 
diff --git a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java
index db821da..d3630f0 100644
--- a/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java
+++ b/viewers/restfulobjects/rendering/src/main/java/org/apache/isis/viewer/restfulobjects/rendering/domainobjects/ObjectActionReprRenderer.java
@@ -172,7 +172,9 @@ public class ObjectActionReprRenderer extends AbstractObjectMemberReprRenderer<O
             final ObjectActionParameter param,
             final InteractionInitiatedBy interactionInitiatedBy) {
         
-        val pendingArgs = param.getAction().newPendingParameterModel(objectAdapter);
+        val pendingArgs = param.getAction()
+                .newPendingParameterModelHead(objectAdapter)
+                .emptyModel();
         
         val choiceAdapters = param.getChoices(pendingArgs, interactionInitiatedBy);
         if (choiceAdapters == null || choiceAdapters.isEmpty()) {
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
index 6883231..f528b87 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ActionModel.java
@@ -69,6 +69,7 @@ import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
+import org.apache.isis.core.metamodel.specloader.specimpl.PendingParameterModel;
 import org.apache.isis.core.webapp.context.IsisWebAppCommonContext;
 import org.apache.isis.viewer.wicket.model.common.PageParametersUtils;
 import org.apache.isis.viewer.wicket.model.mementos.ActionMemento;
@@ -400,7 +401,7 @@ public class ActionModel extends BookmarkableModel<ManagedObject> implements For
         final int i = apm.getNumber();
         ActionArgumentModel actionArgumentModel = arguments.get(i);
         if (actionArgumentModel == null) {
-            actionArgumentModel = new ScalarModel(entityModel, apm);
+            actionArgumentModel = new ScalarParameterModel(entityModel, apm);
             final int number = actionArgumentModel.getParameterMemento().getNumber();
             arguments.put(number, actionArgumentModel);
         }
@@ -506,6 +507,12 @@ public class ActionModel extends BookmarkableModel<ManagedObject> implements For
         throw new UnsupportedOperationException("target adapter for ActionModel cannot be changed");
     }
 
+    public PendingParameterModel getArgumentsAsParamModel() {
+        return getAction().newPendingParameterModelHead(getTargetAdapter())
+                .model(getArgumentsAsImmutable());
+    }
+
+    @Deprecated // make private (use getArgumentsAsParamModel instead)
     public Can<ManagedObject> getArgumentsAsImmutable() {
         
         val objectAction = getAction();
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
index a1dda83..6d3e24c 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/EntityModel.java
@@ -329,7 +329,7 @@ implements ObjectAdapterModel, UiHintContainer, ObjectUiModel {
             final RenderingHint renderingHint) {
         ScalarModel scalarModel = propertyScalarModels.get(pm);
         if (scalarModel == null) {
-            scalarModel = new ScalarModel(this, pm, mode, renderingHint);
+            scalarModel = new ScalarPropertyModel(this, pm, mode, renderingHint);
 
             propertyScalarModels.put(pm, scalarModel);
         }
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java
index 09af95f..f0e8187 100644
--- a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarModel.java
@@ -22,7 +22,6 @@ import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.function.BiFunction;
 
 import org.apache.isis.applib.annotation.PromptStyle;
 import org.apache.isis.applib.annotation.Where;
@@ -34,34 +33,23 @@ import org.apache.isis.core.metamodel.consent.Consent;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.facetapi.Facet;
 import org.apache.isis.core.metamodel.facetapi.FacetHolder;
-import org.apache.isis.core.metamodel.facetapi.FeatureType;
 import org.apache.isis.core.metamodel.facets.object.parseable.ParseableFacet;
 import org.apache.isis.core.metamodel.facets.object.promptStyle.PromptStyleFacet;
-import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
-import org.apache.isis.core.metamodel.facets.objectvalue.fileaccept.FileAcceptFacet;
 import org.apache.isis.core.metamodel.facets.objectvalue.mandatory.MandatoryFacet;
-import org.apache.isis.core.metamodel.facets.objectvalue.typicallen.TypicalLengthFacet;
-import org.apache.isis.core.metamodel.facets.value.bigdecimal.BigDecimalValueFacet;
-import org.apache.isis.core.metamodel.facets.value.string.StringValueSemanticsProvider;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecId;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
-import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
 import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
-import org.apache.isis.core.metamodel.specloader.specimpl.PendingParameterModel;
 import org.apache.isis.core.webapp.context.memento.ObjectMemento;
 import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
 import org.apache.isis.viewer.wicket.model.links.LinksProvider;
 import org.apache.isis.viewer.wicket.model.mementos.ActionParameterMemento;
 import org.apache.isis.viewer.wicket.model.mementos.PropertyMemento;
 
-import lombok.Getter;
-import lombok.Setter;
 import lombok.val;
 
 
-
 /**
  * Represents a scalar of an entity, either a {@link Kind#PROPERTY property} or
  * a {@link Kind#PARAMETER parameter}.
@@ -80,594 +68,32 @@ import lombok.val;
  *     common superclass for both EntityModel and ScalarModel.
  * </p>
  */
-public class ScalarModel extends EntityModel 
-implements LinksProvider, FormExecutorContext, ActionArgumentModel {
+public abstract class ScalarModel extends EntityModel 
+implements LinksProvider, FormExecutorContext {
 
     private static final long serialVersionUID = 1L;
 
     public enum Kind {
-        PROPERTY {
-            @Override
-            public String getName(final ScalarModel scalarModel) {
-                return scalarModel.getPropertyMemento().getProperty(scalarModel.getSpecificationLoader()).getName();
-            }
-
-            @Override
-            public ObjectSpecification getScalarTypeSpec(final ScalarModel scalarModel) {
-                ObjectSpecId type = scalarModel.getPropertyMemento().getType();
-                return scalarModel.getSpecificationLoader().lookupBySpecIdElseLoad(type);
-            }
-
-            @Override
-            public String getIdentifier(final ScalarModel scalarModel) {
-                return scalarModel.getPropertyMemento().getIdentifier();
-            }
-
-            @Override
-            public String getCssClass(final ScalarModel scalarModel) {
-                final String objectSpecId =
-                        scalarModel.getParentEntityModel().getTypeOfSpecification().getSpecId().asString().replace(".", "-");
-                final String propertyId = getIdentifier(scalarModel);
-                return "isis-" + objectSpecId + "-" + propertyId;
-            }
-
-            @Override
-            public boolean whetherHidden(final ScalarModel scalarModel, final Where where) {
-                final ManagedObject parentAdapter = scalarModel.getParentEntityModel().load();
-                final OneToOneAssociation property = scalarModel.getPropertyMemento().getProperty(scalarModel.getSpecificationLoader());
-                try {
-                    final Consent visibility = property.isVisible(parentAdapter, InteractionInitiatedBy.USER, where);
-                    return visibility.isVetoed();
-                } catch (final Exception ex) {
-                    return true; // will be hidden
-                }
-            }
-
-            @Override
-            public String whetherDisabled(final ScalarModel scalarModel, final Where where) {
-                final ManagedObject parentAdapter = scalarModel.getParentEntityModel().load();
-                final OneToOneAssociation property = scalarModel.getPropertyMemento().getProperty(scalarModel.getSpecificationLoader());
-                try {
-                    final Consent usable = property.isUsable(parentAdapter, InteractionInitiatedBy.USER, where);
-                    return usable.isAllowed() ? null : usable.getReason();
-                } catch (final Exception ex) {
-                    return ex.getLocalizedMessage();
-                }
-            }
-
-            @Override
-            public String parseAndValidate(final ScalarModel scalarModel, final String proposedPojoAsStr) {
-                final OneToOneAssociation property = scalarModel.getPropertyMemento().getProperty(scalarModel.getSpecificationLoader());
-                ParseableFacet parseableFacet = property.getFacet(ParseableFacet.class);
-                if (parseableFacet == null) {
-                    parseableFacet = property.getSpecification().getFacet(ParseableFacet.class);
-                }
-                try {
-                    final ManagedObject parentAdapter = scalarModel.getParentEntityModel().load();
-                    final ManagedObject currentValue = property.get(parentAdapter, InteractionInitiatedBy.USER);
-                    final ManagedObject proposedAdapter =
-                            parseableFacet.parseTextEntry(currentValue, proposedPojoAsStr, InteractionInitiatedBy.USER);
-                    final Consent valid = property.isAssociationValid(parentAdapter, proposedAdapter,
-                            InteractionInitiatedBy.USER);
-                    return valid.isAllowed() ? null : valid.getReason();
-//                } catch (final ConcurrencyException ex) {
-//                    // disregard concurrency exceptions because will pick up at the IFormValidator level rather
-//                    // than each individual property.
-//                    return null;
-                } catch (final Exception ex) {
-                    return ex.getLocalizedMessage();
-                }
-            }
-
-            @Override
-            public String validate(final ScalarModel scalarModel, final ManagedObject proposedAdapter) {
-                final ManagedObject parentAdapter = scalarModel.getParentEntityModel().load();
-                final OneToOneAssociation property = scalarModel.getPropertyMemento().getProperty(scalarModel.getSpecificationLoader());
-                try {
-                    final Consent valid = property.isAssociationValid(parentAdapter, proposedAdapter,
-                            InteractionInitiatedBy.USER);
-                    return valid.isAllowed() ? null : valid.getReason();
-                } catch (final Exception ex) {
-                    return ex.getLocalizedMessage();
-                }
-            }
-
-            @Override
-            public boolean isRequired(final ScalarModel scalarModel) {
-                final FacetHolder facetHolder = scalarModel.getPropertyMemento().getProperty(scalarModel.getSpecificationLoader());
-                return isRequired(facetHolder);
-            }
-
-            @Override
-            public <T extends Facet> T getFacet(final ScalarModel scalarModel, final Class<T> facetType) {
-                final FacetHolder facetHolder = scalarModel.getPropertyMemento().getProperty(scalarModel.getSpecificationLoader());
-                return facetHolder.getFacet(facetType);
-            }
-
-            @Override
-            public ManagedObject getDefault(
-                    final ScalarModel scalarModel,
-                    final Can<ManagedObject> pendingArgs) {
-
-                final PropertyMemento propertyMemento = scalarModel.getPropertyMemento();
-                final OneToOneAssociation property = propertyMemento
-                        .getProperty(scalarModel.getSpecificationLoader());
-                ManagedObject parentAdapter = scalarModel.getParentEntityModel().load();
-                return property.getDefault(parentAdapter);
-            }
-
-            @Override
-            public boolean hasChoices(final ScalarModel scalarModel) {
-                final PropertyMemento propertyMemento = scalarModel.getPropertyMemento();
-                final OneToOneAssociation property = propertyMemento.getProperty(scalarModel.getSpecificationLoader());
-                return property.hasChoices();
-            }
-
-            @Override
-            public Can<ManagedObject> getChoices(
-                    final ScalarModel scalarModel,
-                    final Can<ManagedObject> pendingArgs) {
-
-                final PropertyMemento propertyMemento = scalarModel.getPropertyMemento();
-                final OneToOneAssociation property = propertyMemento
-                        .getProperty(scalarModel.getSpecificationLoader());
-                ManagedObject parentAdapter = scalarModel.getParentEntityModel().load();
-                final Can<ManagedObject> choices = property.getChoices(
-                        parentAdapter,
-                        InteractionInitiatedBy.USER);
-
-                return choices;
-            }
-
-            @Override
-            public boolean hasAutoComplete(final ScalarModel scalarModel) {
-                final PropertyMemento propertyMemento = scalarModel.getPropertyMemento();
-                final OneToOneAssociation property = propertyMemento.getProperty(scalarModel.getSpecificationLoader());
-                return property.hasAutoComplete();
-            }
-
-            @Override
-            public Can<ManagedObject> getAutoComplete(
-                    final ScalarModel scalarModel,
-                    final Can<ManagedObject> pendingArgs, // ignored for properties
-                    final String searchArg) {
-
-                final PropertyMemento propertyMemento = scalarModel.getPropertyMemento();
-                final OneToOneAssociation property = propertyMemento.getProperty(scalarModel.getSpecificationLoader());
-                final ManagedObject parentAdapter =
-                        scalarModel.getParentEntityModel().load();
-                final Can<ManagedObject> choices =
-                        property.getAutoComplete(
-                                parentAdapter, 
-                                searchArg,
-                                InteractionInitiatedBy.USER);
-                return choices;
-            }
-
-            @Override
-            public int getAutoCompleteOrChoicesMinLength(ScalarModel scalarModel) {
-
-                if (scalarModel.hasAutoComplete()) {
-                    final PropertyMemento propertyMemento = scalarModel.getPropertyMemento();
-                    final OneToOneAssociation property = propertyMemento.getProperty(scalarModel.getSpecificationLoader());
-                    return property.getAutoCompleteMinLength();
-                } else {
-                    return 0;
-                }
-            }
-
-            @Override
-            public String getDescribedAs(final ScalarModel scalarModel) {
-                final PropertyMemento propertyMemento = scalarModel.getPropertyMemento();
-                final OneToOneAssociation property = propertyMemento.getProperty(scalarModel.getSpecificationLoader());
-                return property.getDescription();
-            }
-
-            @Override
-            public Integer getLength(ScalarModel scalarModel) {
-                final PropertyMemento propertyMemento = scalarModel.getPropertyMemento();
-                final OneToOneAssociation property = propertyMemento.getProperty(scalarModel.getSpecificationLoader());
-                final BigDecimalValueFacet facet = property.getFacet(BigDecimalValueFacet.class);
-                return facet != null? facet.getPrecision(): null;
-            }
-
-            @Override
-            public Integer getScale(ScalarModel scalarModel) {
-                final PropertyMemento propertyMemento = scalarModel.getPropertyMemento();
-                final OneToOneAssociation property = propertyMemento.getProperty(scalarModel.getSpecificationLoader());
-                final BigDecimalValueFacet facet = property.getFacet(BigDecimalValueFacet.class);
-                return facet != null? facet.getScale(): null;
-            }
-
-            @Override
-            public int getTypicalLength(ScalarModel scalarModel) {
-                final PropertyMemento propertyMemento = scalarModel.getPropertyMemento();
-                final OneToOneAssociation property = propertyMemento.getProperty(scalarModel.getSpecificationLoader());
-                final TypicalLengthFacet facet = property.getFacet(TypicalLengthFacet.class);
-                return facet != null? facet.value() : StringValueSemanticsProvider.TYPICAL_LENGTH;
-            }
-
-            @Override
-            public String getFileAccept(ScalarModel scalarModel) {
-                final PropertyMemento propertyMemento = scalarModel.getPropertyMemento();
-                final OneToOneAssociation property = propertyMemento.getProperty(scalarModel.getSpecificationLoader());
-                final FileAcceptFacet facet = property.getFacet(FileAcceptFacet.class);
-                return facet != null? facet.value(): null;
-            }
-
-
-            @Override
-            public void init(final ScalarModel scalarModel) {
-                reset(scalarModel);
-            }
-
-            @Override
-            public void reset(ScalarModel scalarModel) {
-                final OneToOneAssociation property = scalarModel.propertyMemento.getProperty(scalarModel.getSpecificationLoader());
-
-                //XXX lombok issue, no val
-                ManagedObject parentAdapter = scalarModel.getParentEntityModel().load();
-
-                setObjectFromPropertyIfVisible(scalarModel, property, parentAdapter);
-            }
-
-            @Override
-            public ManagedObject load(final ScalarModel scalarModel) {
-                return scalarModel.loadFromSuper();
-            }
-
-            @Override
-            public boolean isCollection(final ScalarModel scalarModel) {
-                return false;
-            }
-
-            @Override
-            public String toStringOf(final ScalarModel scalarModel) {
-                return this.name() + ": " + scalarModel.getPropertyMemento().toString();
-            }
-        },
-        PARAMETER {
-            @Override
-            public String getName(final ScalarModel scalarModel) {
-                return scalarModel.getParameterMemento().getActionParameter(scalarModel.getSpecificationLoader()).getName();
-            }
-
-            @Override
-            public ObjectSpecification getScalarTypeSpec(final ScalarModel scalarModel) {
-                return scalarModel.getParameterMemento().getSpecification(scalarModel.getSpecificationLoader());
-            }
-
-            @Override
-            public String getIdentifier(final ScalarModel scalarModel) {
-                return "" + scalarModel.getParameterMemento().getNumber();
-            }
-
-            @Override
-            public String getCssClass(final ScalarModel scalarModel) {
-                final ObjectMemento adapterMemento = scalarModel.getObjectAdapterMemento();
-                if (adapterMemento == null) {
-                    // shouldn't happen
-                    return null;
-                }
-                final ObjectActionParameter actionParameter = scalarModel.getParameterMemento()
-                        .getActionParameter(scalarModel.getSpecificationLoader());
-                final ObjectAction action = actionParameter.getAction();
-                final String objectSpecId = action.getOnType().getSpecId().asString().replace(".", "-");
-                final String parmId = actionParameter.getId();
-
-                return "isis-" + objectSpecId + "-" + action.getId() + "-" + parmId;
-            }
-
-            @Override
-            public String whetherDisabled(final ScalarModel scalarModel, Where where) {
-                // always enabled
-                return null;
-            }
-
-            @Override
-            public boolean whetherHidden(final ScalarModel scalarModel, Where where) {
-                // always enabled
-                return false;
-            }
-
-            @Override
-            public String parseAndValidate(final ScalarModel scalarModel, final String proposedPojoAsStr) {
-                final ObjectActionParameter parameter = scalarModel.getParameterMemento().getActionParameter(
-                        scalarModel.getSpecificationLoader());
-                try {
-                    //XXX lombok issue, no val
-                    ManagedObject parentAdapter = scalarModel.getParentEntityModel().load();
-                    final String invalidReasonIfAny = parameter.isValid(parentAdapter, proposedPojoAsStr,
-                            InteractionInitiatedBy.USER
-                            );
-                    return invalidReasonIfAny;
-                } catch (final Exception ex) {
-                    return ex.getLocalizedMessage();
-                }
-            }
-
-            @Override
-            public String validate(final ScalarModel scalarModel, final ManagedObject proposedAdapter) {
-                final ObjectActionParameter parameter = scalarModel.getParameterMemento().getActionParameter(
-                        scalarModel.getSpecificationLoader());
-                try {
-                    //XXX lombok issue, no val
-                    ManagedObject parentAdapter = scalarModel.getParentEntityModel().load();
-                    final String invalidReasonIfAny = parameter.isValid(parentAdapter, proposedAdapter.getPojo(),
-                            InteractionInitiatedBy.USER
-                            );
-                    return invalidReasonIfAny;
-                } catch (final Exception ex) {
-                    return ex.getLocalizedMessage();
-                }
-            }
-
-            @Override
-            public boolean isRequired(final ScalarModel scalarModel) {
-                final FacetHolder facetHolder = scalarModel.getParameterMemento().getActionParameter(
-                        scalarModel.getSpecificationLoader());
-                return isRequired(facetHolder);
-            }
-
-            @Override
-            public <T extends Facet> T getFacet(final ScalarModel scalarModel, final Class<T> facetType) {
-                final FacetHolder facetHolder = scalarModel.getParameterMemento().getActionParameter(
-                        scalarModel.getSpecificationLoader());
-                return facetHolder.getFacet(facetType);
-            }
-
-            @Override
-            public ManagedObject getDefault(
-                    final ScalarModel scalarModel,
-                    final Can<ManagedObject> pendingArgs) {
-                
-                return withPendingParamsDo(scalarModel, pendingArgs, (pendingParamsModel, actionParameter)->
-                actionParameter.getDefault(
-                        pendingParamsModel));
-            }
-
-            @Override
-            public boolean hasChoices(final ScalarModel scalarModel) {
-                final ActionParameterMemento parameterMemento = scalarModel.getParameterMemento();
-                final ObjectActionParameter actionParameter = parameterMemento.getActionParameter(scalarModel.getSpecificationLoader());
-                return actionParameter.hasChoices();
-            }
-            @Override
-            public Can<ManagedObject> getChoices(
-                    final ScalarModel scalarModel,
-                    final Can<ManagedObject> pendingArgs) {
-                
-                return withPendingParamsDo(scalarModel, pendingArgs, (pendingParamsModel, actionParameter)->
-                actionParameter.getChoices(
-                        pendingParamsModel,
-                        InteractionInitiatedBy.USER));
-                
-            }
-
-            @Override
-            public boolean hasAutoComplete(final ScalarModel scalarModel) {
-                final ActionParameterMemento parameterMemento = scalarModel.getParameterMemento();
-                final ObjectActionParameter actionParameter = parameterMemento.getActionParameter(scalarModel.getSpecificationLoader());
-                return actionParameter.hasAutoComplete();
-            }
-            @Override
-            public Can<ManagedObject> getAutoComplete(
-                    final ScalarModel scalarModel,
-                    final Can<ManagedObject> pendingArgs,
-                    final String searchArg) {
-                
-                return withPendingParamsDo(scalarModel, pendingArgs, (pendingParamsModel, actionParameter)->
-                actionParameter.getAutoComplete(
-                        pendingParamsModel,
-                        searchArg,
-                        InteractionInitiatedBy.USER)); 
-            }
-
-
-            
-            @Override
-            public int getAutoCompleteOrChoicesMinLength(ScalarModel scalarModel) {
-                if (scalarModel.hasAutoComplete()) {
-                    final ActionParameterMemento parameterMemento = scalarModel.getParameterMemento();
-                    final ObjectActionParameter actionParameter = parameterMemento.getActionParameter(
-                            scalarModel.getSpecificationLoader());
-                    return actionParameter.getAutoCompleteMinLength();
-                } else {
-                    return 0;
-                }
-            }
-
-            @Override
-            public String getDescribedAs(final ScalarModel scalarModel) {
-                final ActionParameterMemento parameterMemento = scalarModel.getParameterMemento();
-                final ObjectActionParameter actionParameter = parameterMemento.getActionParameter(scalarModel.getSpecificationLoader());
-                return actionParameter.getDescription();
-            }
-
-            @Override
-            public Integer getLength(ScalarModel scalarModel) {
-                final ActionParameterMemento parameterMemento = scalarModel.getParameterMemento();
-                final ObjectActionParameter actionParameter = parameterMemento.getActionParameter(scalarModel.getSpecificationLoader());
-                final BigDecimalValueFacet facet = actionParameter.getFacet(BigDecimalValueFacet.class);
-                return facet != null? facet.getPrecision(): null;
-            }
-
-            @Override
-            public Integer getScale(ScalarModel scalarModel) {
-                final ActionParameterMemento parameterMemento = scalarModel.getParameterMemento();
-                final ObjectActionParameter actionParameter = parameterMemento.getActionParameter(scalarModel.getSpecificationLoader());
-                final BigDecimalValueFacet facet = actionParameter.getFacet(BigDecimalValueFacet.class);
-                return facet != null? facet.getScale(): null;
-            }
-
-            @Override
-            public int getTypicalLength(ScalarModel scalarModel) {
-                final ActionParameterMemento parameterMemento = scalarModel.getParameterMemento();
-                final ObjectActionParameter actionParameter = parameterMemento.getActionParameter(scalarModel.getSpecificationLoader());
-                final TypicalLengthFacet facet = actionParameter.getFacet(TypicalLengthFacet.class);
-                return facet != null? facet.value() : StringValueSemanticsProvider.TYPICAL_LENGTH;
-            }
-
-
-            @Override
-            public String getFileAccept(ScalarModel scalarModel) {
-                final ActionParameterMemento parameterMemento = scalarModel.getParameterMemento();
-                final ObjectActionParameter actionParameter = parameterMemento.getActionParameter(scalarModel.getSpecificationLoader());
-                final FileAcceptFacet facet = actionParameter.getFacet(FileAcceptFacet.class);
-                return facet != null? facet.value(): null;
-            }
-
-            @Override
-            public void init(final ScalarModel scalarModel) {
-                // no-op
-            }
-
-            @Override
-            public void reset(ScalarModel scalarModel) {
-                final ObjectActionParameter actionParameter = scalarModel.parameterMemento.getActionParameter(
-                        scalarModel.getSpecificationLoader());
-                final ManagedObject parentAdapter =
-                        scalarModel.getParentEntityModel().load();
-                final ManagedObject defaultAdapter = actionParameter.getDefault(parentAdapter);
-                scalarModel.setObject(defaultAdapter);
-            }
-
-            @Override
-            public ManagedObject load(final ScalarModel scalarModel) {
-                final ActionParameterMemento parameterMemento = scalarModel.getParameterMemento();
-                final ObjectActionParameter actionParameter = parameterMemento
-                        .getActionParameter(scalarModel.getSpecificationLoader());
-                final ManagedObject objectAdapter = scalarModel.loadFromSuper();
-
-                if(objectAdapter != null) {
-                    return objectAdapter;
-                }
-                if(actionParameter.getFeatureType() == FeatureType.ACTION_PARAMETER_SCALAR) {
-                    return objectAdapter;
-                }
-
-
-                // hmmm... I think we should simply return null, as an indicator that there is no "pending" (see ScalarModelWithMultiPending)
-
-                //                // return an empty collection
-                //                // TODO: this should probably move down into OneToManyActionParameter impl
-                //                final OneToManyActionParameter otmap = (OneToManyActionParameter) actionParameter;
-                //                final CollectionSemantics collectionSemantics = otmap.getCollectionSemantics();
-                //                final TypeOfFacet typeOfFacet = actionParameter.getFacet(TypeOfFacet.class);
-                //                final Class<?> elementType = typeOfFacet.value();
-                //                final Object emptyCollection = collectionSemantics.emptyCollectionOf(elementType);
-                //                return scalarModel.getCurrentSession().getPersistenceSession().adapterFor(emptyCollection);
-
-                return objectAdapter;
-
-            }
-
-            @Override
-            public boolean isCollection(final ScalarModel scalarModel) {
-                final ActionParameterMemento parameterMemento = scalarModel.getParameterMemento();
-                final ObjectActionParameter actionParameter = parameterMemento.getActionParameter(scalarModel.getSpecificationLoader());
-                return actionParameter.getFeatureType() == FeatureType.ACTION_PARAMETER_COLLECTION;
-            }
-
-            @Override
-            public String toStringOf(final ScalarModel scalarModel) {
-                return this.name() + ": " + scalarModel.getParameterMemento().toString();
-            }
-
-        };
-
-        public abstract String getName(ScalarModel scalarModel);
-
-        public abstract ObjectSpecification getScalarTypeSpec(ScalarModel scalarModel);
-
-        public abstract String getIdentifier(ScalarModel scalarModel);
-
-        public abstract boolean whetherHidden(ScalarModel scalarModel, Where where);
-
-        public abstract String whetherDisabled(ScalarModel scalarModel, Where where);
-
-        public abstract String parseAndValidate(ScalarModel scalarModel, String proposedPojoAsStr);
-
-        public abstract String validate(ScalarModel scalarModel, ManagedObject proposedAdapter);
-
-        public abstract String getCssClass(ScalarModel scalarModel);
-
-        public abstract boolean isRequired(ScalarModel scalarModel);
-
-        public abstract <T extends Facet> T getFacet(ScalarModel scalarModel, Class<T> facetType);
-
-        static boolean isRequired(final FacetHolder facetHolder) {
-            final MandatoryFacet mandatoryFacet = facetHolder.getFacet(MandatoryFacet.class);
-            final boolean required = mandatoryFacet != null && !mandatoryFacet.isInvertedSemantics();
-            return required;
-        }
-
-        public abstract ManagedObject getDefault(
-                ScalarModel scalarModel,
-                Can<ManagedObject> pendingArgs);
-
-        public abstract boolean hasChoices(ScalarModel scalarModel);
-        public abstract Can<ManagedObject> getChoices(
-                ScalarModel scalarModel,
-                Can<ManagedObject> pendingArgs);
-
-        public abstract boolean hasAutoComplete(ScalarModel scalarModel);
-        public abstract Can<ManagedObject> getAutoComplete(
-                ScalarModel scalarModel,
-                Can<ManagedObject> pendingArgs,
-                String searchArg);
-
-        public abstract int getAutoCompleteOrChoicesMinLength(ScalarModel scalarModel);
-
-        public abstract String getDescribedAs(ScalarModel scalarModel);
-
-        public abstract Integer getLength(ScalarModel scalarModel);
-        public abstract Integer getScale(ScalarModel scalarModel);
-
-        public abstract int getTypicalLength(ScalarModel scalarModel);
-
-        public abstract String getFileAccept(ScalarModel scalarModel);
-
-        public abstract void init(ScalarModel scalarModel);
-        public abstract void reset(ScalarModel scalarModel);
-
-        public abstract ManagedObject load(final ScalarModel scalarModel);
-
-        public abstract boolean isCollection(final ScalarModel scalarModel);
+        PROPERTY,
+        PARAMETER;
+    }
 
-        public abstract String toStringOf(final ScalarModel scalarModel);
+    static boolean isRequired(final FacetHolder facetHolder) {
+        final MandatoryFacet mandatoryFacet = facetHolder.getFacet(MandatoryFacet.class);
+        final boolean required = mandatoryFacet != null && !mandatoryFacet.isInvertedSemantics();
+        return required;
     }
 
     private final Kind kind;
 
     private final EntityModel parentEntityModel;
 
-    @Override
-    public ManagedObject load() {
-        return kind.load(this);
-    }
-
-    private ManagedObject loadFromSuper() {
-        return super.load();
-    }
-
-
-    /**
-     * Populated only if {@link #getKind()} is {@link Kind#PARAMETER}
-     */
-    private ActionParameterMemento parameterMemento;
-
-    /**
-     * Populated only if {@link #getKind()} is {@link Kind#PROPERTY}
-     */
-    private PropertyMemento propertyMemento;
-
     /**
      * Creates a model representing an action parameter of an action of a parent
      * object, with the {@link #getObject() value of this model} to be default
      * value (if any) of that action parameter.
      */
-    public ScalarModel(EntityModel parentEntityModel, ActionParameterMemento apm) {
+    protected ScalarModel(EntityModel parentEntityModel, ActionParameterMemento apm) {
         
         super(parentEntityModel.getCommonContext(),
                 EntityModel.Mode.EDIT, 
@@ -675,9 +101,6 @@ implements LinksProvider, FormExecutorContext, ActionArgumentModel {
         
         this.kind = Kind.PARAMETER;
         this.parentEntityModel = parentEntityModel;
-        this.parameterMemento = apm;
-
-        init();
     }
 
     /**
@@ -685,7 +108,7 @@ implements LinksProvider, FormExecutorContext, ActionArgumentModel {
      * {@link #getObject() value of this model} to be current value of the
      * property.
      */
-    public ScalarModel(
+    protected ScalarModel(
             EntityModel parentEntityModel, 
             PropertyMemento pm,
             EntityModel.Mode mode, 
@@ -694,19 +117,10 @@ implements LinksProvider, FormExecutorContext, ActionArgumentModel {
         super(parentEntityModel.getCommonContext(), mode, renderingHint);
         this.kind = Kind.PROPERTY;
         this.parentEntityModel = parentEntityModel;
-        this.propertyMemento = pm;
-
-        init();
-        getAndStore(parentEntityModel);
-    }
-
-    private void init() {
-        kind.init(this);
     }
 
-    @Override
-    public void reset() {
-        kind.reset(this);
+    protected ManagedObject loadFromSuper() {
+        return super.load();
     }
 
     @Override
@@ -714,14 +128,9 @@ implements LinksProvider, FormExecutorContext, ActionArgumentModel {
         return parentEntityModel;
     }
 
-    private void getAndStore(final EntityModel parentEntityModel) {
-        final ObjectMemento parentAdapterMemento = parentEntityModel.getObjectAdapterMemento();
-        final OneToOneAssociation property = propertyMemento.getProperty(getSpecificationLoader());
-        final ManagedObject parentAdapter = super.getCommonContext().reconstructObject(parentAdapterMemento); 
-        setObjectFromPropertyIfVisible(ScalarModel.this, property, parentAdapter);
-    }
 
-    private static void setObjectFromPropertyIfVisible(
+
+    protected static void setObjectFromPropertyIfVisible(
             final ScalarModel scalarModel,
             final OneToOneAssociation property,
             final ManagedObject parentAdapter) {
@@ -741,10 +150,7 @@ implements LinksProvider, FormExecutorContext, ActionArgumentModel {
         scalarModel.setObject(associatedAdapter);
     }
 
-
-    public boolean isCollection() {
-        return kind.isCollection(this);
-    }
+    public abstract boolean isCollection();
 
     /**
      * Whether the scalar represents a {@link Kind#PROPERTY property} or a
@@ -754,24 +160,7 @@ implements LinksProvider, FormExecutorContext, ActionArgumentModel {
         return kind;
     }
 
-    public String getName() {
-        return kind.getName(this);
-    }
-
-    /**
-     * Populated only if {@link #getKind()} is {@link Kind#PROPERTY}
-     */
-    public PropertyMemento getPropertyMemento() {
-        return propertyMemento;
-    }
-
-    /**
-     * Populated only if {@link #getKind()} is {@link Kind#PARAMETER}
-     */
-    @Override
-    public ActionParameterMemento getParameterMemento() {
-        return parameterMemento;
-    }
+    public abstract String getName();
 
     /**
      * Overrides superclass' implementation, because a {@link ScalarModel} can
@@ -781,7 +170,7 @@ implements LinksProvider, FormExecutorContext, ActionArgumentModel {
      */
     @Override
     public ObjectSpecification getTypeOfSpecification() {
-        return kind.getScalarTypeSpec(this);
+        return getScalarTypeSpec();
     }
 
     public boolean isScalarTypeAnyOf(final Class<?>... requiredClass) {
@@ -853,91 +242,53 @@ implements LinksProvider, FormExecutorContext, ActionArgumentModel {
         }
     }
 
-    // pending args helper
-    private static <T> T withPendingParamsDo(
-            final ScalarModel scalarModel,
-            final Can<ManagedObject> pendingArgs,
-            final BiFunction<PendingParameterModel, ObjectActionParameter, T> function) {
-        
-        val parameterMemento = scalarModel.getParameterMemento();
-        val actionParameter = parameterMemento.getActionParameter(scalarModel.getSpecificationLoader());
-        val actionOwner = scalarModel.getParentEntityModel().load();
-        val pendingParamsModel = actionParameter.getAction().newPendingParameterModel(actionOwner, pendingArgs);
-        return function.apply(pendingParamsModel, actionParameter);
-    }
+
     
     public boolean whetherHidden() {
         final Where where = getRenderingHint().asWhere();
-        return kind.whetherHidden(this, where);
+        return whetherHidden(where);
     }
 
+    protected abstract boolean whetherHidden(Where where);
+
     public String whetherDisabled() {
         final Where where = getRenderingHint().asWhere();
-        return kind.whetherDisabled(this, where);
+        return whetherDisabled(where);
     }
 
-    public String validate(final ManagedObject proposedAdapter) {
-        return kind.validate(this, proposedAdapter);
-    }
+    protected abstract String whetherDisabled(Where where);
 
-    public boolean isRequired() {
-        return kind.isRequired(this);
-    }
+    public abstract String validate(ManagedObject proposedAdapter);
 
-    public String getCssClass() {
-        return kind.getCssClass(this);
-    }
+    public abstract boolean isRequired();
 
-    public <T extends Facet> T getFacet(final Class<T> facetType) {
-        return kind.getFacet(this, facetType);
-    }
-
-    public String getDescribedAs() {
-        return kind.getDescribedAs(this);
-    }
+    public abstract String getCssClass();
 
-    public String getFileAccept() {
-        return kind.getFileAccept(this);
-    }
+    public abstract <T extends Facet> T getFacet(Class<T> facetType);
 
-    public boolean hasChoices() {
-        return kind.hasChoices(this);
-    }
+    public abstract String getDescribedAs();
 
-    public Can<ManagedObject> getChoices(
-            final Can<ManagedObject> pendingArgs) {
-        
-        return kind.getChoices(this, pendingArgs);
-    }
+    public abstract String getFileAccept();
 
-    public boolean hasAutoComplete() {
-        return kind.hasAutoComplete(this);
-    }
+    public abstract boolean hasChoices();
+    public abstract Can<ManagedObject> getChoices(Can<ManagedObject> pendingArgs);
 
-    public Can<ManagedObject> getAutoComplete(
-            final Can<ManagedObject> pendingArgs,
-            final String searchTerm) {
-        
-        return kind.getAutoComplete(this, pendingArgs, searchTerm);
-    }
+    public abstract boolean hasAutoComplete();
+    public abstract Can<ManagedObject> getAutoComplete(Can<ManagedObject> pendingArg, String searchTerm);
 
     /**
      * for {@link BigDecimal}s only.
      *
      * @see #getScale()
      */
-    public int getLength() {
-        return kind.getLength(this);
-    }
+    public abstract Integer getLength();
 
     /**
      * for {@link BigDecimal}s only.
      *
      * @see #getLength()
      */
-    public Integer getScale() {
-        return kind.getScale(this);
-    }
+    public abstract Integer getScale();
 
     /**
      * Additional links to render (if any)
@@ -952,13 +303,6 @@ implements LinksProvider, FormExecutorContext, ActionArgumentModel {
     /**
      * @return
      */
-    public int getAutoCompleteMinLength() {
-        return kind.getAutoCompleteOrChoicesMinLength(this);
-    }
-
-    /**
-     * @return
-     */
     public ScalarModelWithPending asScalarModelWithPending() {
         return new ScalarModelWithPending(){
 
@@ -1038,68 +382,9 @@ implements LinksProvider, FormExecutorContext, ActionArgumentModel {
         return whetherDisabled() == null;
     }
 
-    public String getReasonInvalidIfAny() {
-        //XXX lombok issue, no val 
-        OneToOneAssociation property = getPropertyMemento().getProperty(getSpecificationLoader());
-        ManagedObject adapter = getParentEntityModel().load();
-        ManagedObject associate = getObject();
-        Consent validity = property.isAssociationValid(adapter, associate, InteractionInitiatedBy.USER);
-        return validity.isAllowed() ? null : validity.getReason();
-    }
 
-    /**
-     * Apply changes to the underlying adapter (possibly returning a new adapter).
-     *
-     * @return adapter, which may be different from the original (if a {@link ViewModelFacet#isCloneable(Object) cloneable} view model, for example.
-     */
-    public ManagedObject applyValue(ManagedObject adapter) {
-        //XXX lombok issue, no val
-        OneToOneAssociation property = getPropertyMemento().getProperty(getSpecificationLoader());
-
-        //
-        // previously there was a guard here to only apply changes provided:
-        //
-        // property.containsDoOpFacet(NotPersistedFacet.class) == null
-        //
-        // however, that logic is wrong; although a property may not be directly
-        // persisted so far as JDO is concerned, it may be indirectly persisted
-        // as the result of business logic in the setter.
-        //
-        // for example, see ExampleTaggableEntity (in isisaddons-module-tags).
-        //
-
-        //
-        // previously (prior to XML layouts and 'single property' edits) we also used to check if
-        // the property was disabled, using:
-        //
-        // if(property.containsDoOpFacet(DisabledFacet.class)) {
-        //    // skip, as per comments above
-        //    return;
-        // }
-        //
-        // However, this would seem to be wrong, because the presence of a DisabledFacet doesn't necessarily mean
-        // that the property is disabled (its disabledReason(...) might return null).
-        //
-        // In any case, the only code that calls this method already does the check, so think this is safe
-        // to just remove.
-
-        //XXX lombok issue, no val
-        ManagedObject associate = getObject();
-        property.set(adapter, associate, InteractionInitiatedBy.USER);
-
-        final ViewModelFacet recreatableObjectFacet = adapter.getSpecification().getFacet(ViewModelFacet.class);
-        if(recreatableObjectFacet != null) {
-            final Object viewModel = adapter.getPojo();
-            final boolean cloneable = recreatableObjectFacet.isCloneable(viewModel);
-            if(cloneable) {
-                //XXX lombok issue, no val
-                Object newViewModelPojo = recreatableObjectFacet.clone(viewModel);
-                adapter = super.getPojoToAdapter().apply(newViewModelPojo);
-            }
-        }
 
-        return adapter;
-    }
+
 
     @Override
     protected void onDetach() {
@@ -1136,7 +421,7 @@ implements LinksProvider, FormExecutorContext, ActionArgumentModel {
         this.inlinePromptContext = inlinePromptContext;
     }
 
-    private transient AssociatedActions associatedActions;
+    protected transient AssociatedActions associatedActions;
 
     public static class AssociatedActions {
         private final ObjectAction firstAssociatedWithInlineAsIfEdit;
@@ -1172,28 +457,6 @@ implements LinksProvider, FormExecutorContext, ActionArgumentModel {
         }
     }
 
-    public AssociatedActions associatedActionsIfProperty() {
-        if (associatedActions == null) {
-            associatedActions = new AssociatedActions(calcAssociatedActionsIfProperty());
-        }
-        return associatedActions;
-    }
-
-    private List<ObjectAction> calcAssociatedActionsIfProperty() {
-
-        if (getKind() != Kind.PROPERTY) {
-            return Collections.emptyList();
-        }
-
-        final EntityModel parentEntityModel1 = this.getParentEntityModel();
-        final ManagedObject parentAdapter = parentEntityModel1.load();
-
-        final OneToOneAssociation oneToOneAssociation =
-                this.getPropertyMemento().getProperty(this.getSpecificationLoader());
-
-        return ObjectAction.Util.findForAssociation(parentAdapter, oneToOneAssociation);
-    }
-
 
     /**
      * Whether this model should be surfaced in the UI using a widget rendered such that it is either already in
@@ -1203,9 +466,9 @@ implements LinksProvider, FormExecutorContext, ActionArgumentModel {
      * @return <tt>true</tt> if the widget for this model must be editable.
      */
     public boolean mustBeEditable() {
-        return getMode() == Mode.EDIT ||
-                associatedActionsIfProperty().hasAssociatedActionWithInlineAsIfEdit() ||
-                getKind() == Kind.PARAMETER;
+        return getMode() == Mode.EDIT 
+                || getKind() == Kind.PARAMETER
+                || hasAssociatedActionWithInlineAsIfEdit();
     }
 
     /**
@@ -1217,21 +480,44 @@ implements LinksProvider, FormExecutorContext, ActionArgumentModel {
      */
     @Override
     public boolean isInlinePrompt() {
-        return (getPromptStyle().isInline() && canEnterEditMode()) ||
-                associatedActionsIfProperty().hasAssociatedActionWithInlineAsIfEdit();
+        return (getPromptStyle().isInline() && canEnterEditMode()) 
+                || hasAssociatedActionWithInlineAsIfEdit();
     }
 
-    /**
-     * The initial call of choicesXxx() for any given scalar argument needs the current values
-     * of all args (possibly as initialized through a defaultNXxx().
-     * @implNote transient because only temporary hint.
-     */
-    @Getter @Setter
-    private transient Can<ManagedObject> actionArgsHint;
-
-
     @Override
     public String toString() {
-        return kind.toStringOf(this);
+        return toStringOf();
     }
+
+    protected abstract String toStringOf();
+
+    protected abstract ObjectSpecification getScalarTypeSpec();
+
+    protected abstract String getIdentifier();
+
+    protected abstract String parseAndValidate(String proposedPojoAsStr);
+
+    protected abstract int getTypicalLength();
+
+    public abstract int getAutoCompleteOrChoicesMinLength();
+
+    public abstract ManagedObject getDefault(Can<ManagedObject> pendingArgs);
+
+    public int getAutoCompleteMinLength() {
+        return getAutoCompleteOrChoicesMinLength();
+    }
+
+    public AssociatedActions getAssociatedActions() {
+        if (associatedActions == null) {
+            associatedActions = new AssociatedActions(calcAssociatedActions());
+        }
+        return associatedActions;
+    }
+    
+    protected abstract List<ObjectAction> calcAssociatedActions();
+    
+    public final boolean hasAssociatedActionWithInlineAsIfEdit() {
+        return getAssociatedActions().hasAssociatedActionWithInlineAsIfEdit();
+    }
+    
 }
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarParameterModel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarParameterModel.java
new file mode 100644
index 0000000..b5e2f7d
--- /dev/null
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarParameterModel.java
@@ -0,0 +1,328 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.viewer.wicket.model.models;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.function.BiFunction;
+
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.core.commons.collections.Can;
+import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facetapi.FeatureType;
+import org.apache.isis.core.metamodel.facets.objectvalue.fileaccept.FileAcceptFacet;
+import org.apache.isis.core.metamodel.facets.objectvalue.typicallen.TypicalLengthFacet;
+import org.apache.isis.core.metamodel.facets.value.bigdecimal.BigDecimalValueFacet;
+import org.apache.isis.core.metamodel.facets.value.string.StringValueSemanticsProvider;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
+import org.apache.isis.core.metamodel.specloader.specimpl.PendingParameterModel;
+import org.apache.isis.core.webapp.context.memento.ObjectMemento;
+import org.apache.isis.viewer.wicket.model.mementos.ActionParameterMemento;
+
+import lombok.Getter;
+import lombok.NonNull;
+import lombok.Setter;
+import lombok.val;
+
+public class ScalarParameterModel extends ScalarModel
+implements ActionArgumentModel {
+
+    private static final long serialVersionUID = 1L;
+    
+    @Getter private final ActionParameterMemento parameterMemento;
+    /**
+     * The initial call of choicesXxx() for any given scalar argument needs the current values
+     * of all args (possibly as initialized through a defaultNXxx().
+     * @implNote transient because only temporary hint.
+     */
+    @Getter @Setter
+    private transient Can<ManagedObject> actionArgsHint;
+
+    /**
+     * Creates a model representing an action parameter of an action of a parent
+     * object, with the {@link #getObject() value of this model} to be default
+     * value (if any) of that action parameter.
+     */
+    public ScalarParameterModel(EntityModel parentEntityModel, ActionParameterMemento apm) {
+        super(parentEntityModel, apm);
+        this.parameterMemento = apm;
+    }
+    
+
+    @Override
+    public String getName() {
+        return getParameterMemento().getActionParameter(getSpecificationLoader()).getName();
+    }
+
+    @Override
+    public ObjectSpecification getScalarTypeSpec() {
+        return getParameterMemento().getSpecification(getSpecificationLoader());
+    }
+
+    @Override
+    public String getIdentifier() {
+        return "" + getParameterMemento().getNumber();
+    }
+
+    @Override
+    public String getCssClass() {
+        final ObjectMemento adapterMemento = getObjectAdapterMemento();
+        if (adapterMemento == null) {
+            // shouldn't happen
+            return null;
+        }
+        final ObjectActionParameter actionParameter = getParameterMemento()
+                .getActionParameter(getSpecificationLoader());
+        final ObjectAction action = actionParameter.getAction();
+        final String objectSpecId = action.getOnType().getSpecId().asString().replace(".", "-");
+        final String parmId = actionParameter.getId();
+
+        return "isis-" + objectSpecId + "-" + action.getId() + "-" + parmId;
+    }
+
+    @Override
+    public String whetherDisabled(Where where) {
+        // always enabled
+        return null;
+    }
+
+    @Override
+    public boolean whetherHidden(Where where) {
+        // always enabled
+        return false;
+    }
+
+    @Override
+    public String parseAndValidate(final String proposedPojoAsStr) {
+        final ObjectActionParameter parameter = getParameterMemento().getActionParameter(
+                getSpecificationLoader());
+        try {
+            //XXX lombok issue, no val
+            ManagedObject parentAdapter = getParentEntityModel().load();
+            final String invalidReasonIfAny = parameter.isValid(parentAdapter, proposedPojoAsStr,
+                    InteractionInitiatedBy.USER
+                    );
+            return invalidReasonIfAny;
+        } catch (final Exception ex) {
+            return ex.getLocalizedMessage();
+        }
+    }
+
+    @Override
+    public String validate(final ManagedObject proposedAdapter) {
+        final ObjectActionParameter parameter = getParameterMemento().getActionParameter(
+                getSpecificationLoader());
+        try {
+            //XXX lombok issue, no val
+            ManagedObject parentAdapter = getParentEntityModel().load();
+            final String invalidReasonIfAny = parameter.isValid(parentAdapter, proposedAdapter.getPojo(),
+                    InteractionInitiatedBy.USER
+                    );
+            return invalidReasonIfAny;
+        } catch (final Exception ex) {
+            return ex.getLocalizedMessage();
+        }
+    }
+
+    @Override
+    public boolean isRequired() {
+        final FacetHolder facetHolder = getParameterMemento().getActionParameter(
+                getSpecificationLoader());
+        return isRequired(facetHolder);
+    }
+
+    @Override
+    public <T extends Facet> T getFacet(final Class<T> facetType) {
+        final FacetHolder facetHolder = getParameterMemento().getActionParameter(
+                getSpecificationLoader());
+        return facetHolder.getFacet(facetType);
+    }
+
+    @Override
+    public ManagedObject getDefault(
+            @NonNull final Can<ManagedObject> pendingArgs) {
+        
+        return withPendingParamsDo(pendingArgs, (pendingParamsModel, actionParameter)->
+        actionParameter.getDefault(
+                pendingParamsModel));
+    }
+
+    @Override
+    public boolean hasChoices() {
+        final ActionParameterMemento parameterMemento = getParameterMemento();
+        final ObjectActionParameter actionParameter = parameterMemento.getActionParameter(getSpecificationLoader());
+        return actionParameter.hasChoices();
+    }
+    @Override
+    public Can<ManagedObject> getChoices(
+            @NonNull final Can<ManagedObject> pendingArgs) {
+        
+        return withPendingParamsDo(pendingArgs, (pendingParamsModel, actionParameter)->
+        actionParameter.getChoices(
+                pendingParamsModel,
+                InteractionInitiatedBy.USER));
+        
+    }
+
+    @Override
+    public boolean hasAutoComplete() {
+        final ActionParameterMemento parameterMemento = getParameterMemento();
+        final ObjectActionParameter actionParameter = parameterMemento.getActionParameter(getSpecificationLoader());
+        return actionParameter.hasAutoComplete();
+    }
+    @Override
+    public Can<ManagedObject> getAutoComplete(
+            @NonNull final Can<ManagedObject> pendingArgs,
+            final String searchArg) {
+        
+        return withPendingParamsDo(pendingArgs, (pendingParamsModel, actionParameter)->
+        actionParameter.getAutoComplete(
+                pendingParamsModel,
+                searchArg,
+                InteractionInitiatedBy.USER)); 
+    }
+
+
+    
+    @Override
+    public int getAutoCompleteOrChoicesMinLength() {
+        if (hasAutoComplete()) {
+            final ActionParameterMemento parameterMemento = getParameterMemento();
+            final ObjectActionParameter actionParameter = parameterMemento.getActionParameter(
+                    getSpecificationLoader());
+            return actionParameter.getAutoCompleteMinLength();
+        } else {
+            return 0;
+        }
+    }
+
+    @Override
+    public String getDescribedAs() {
+        final ActionParameterMemento parameterMemento = getParameterMemento();
+        final ObjectActionParameter actionParameter = parameterMemento.getActionParameter(getSpecificationLoader());
+        return actionParameter.getDescription();
+    }
+
+    @Override
+    public Integer getLength() {
+        final ActionParameterMemento parameterMemento = getParameterMemento();
+        final ObjectActionParameter actionParameter = parameterMemento.getActionParameter(getSpecificationLoader());
+        final BigDecimalValueFacet facet = actionParameter.getFacet(BigDecimalValueFacet.class);
+        return facet != null? facet.getPrecision(): null;
+    }
+
+    @Override
+    public Integer getScale() {
+        final ActionParameterMemento parameterMemento = getParameterMemento();
+        final ObjectActionParameter actionParameter = parameterMemento.getActionParameter(getSpecificationLoader());
+        final BigDecimalValueFacet facet = actionParameter.getFacet(BigDecimalValueFacet.class);
+        return facet != null? facet.getScale(): null;
+    }
+
+    @Override
+    public int getTypicalLength() {
+        final ActionParameterMemento parameterMemento = getParameterMemento();
+        final ObjectActionParameter actionParameter = parameterMemento.getActionParameter(getSpecificationLoader());
+        final TypicalLengthFacet facet = actionParameter.getFacet(TypicalLengthFacet.class);
+        return facet != null? facet.value() : StringValueSemanticsProvider.TYPICAL_LENGTH;
+    }
+
+
+    @Override
+    public String getFileAccept() {
+        final ActionParameterMemento parameterMemento = getParameterMemento();
+        final ObjectActionParameter actionParameter = parameterMemento.getActionParameter(getSpecificationLoader());
+        final FileAcceptFacet facet = actionParameter.getFacet(FileAcceptFacet.class);
+        return facet != null? facet.value(): null;
+    }
+
+    @Override
+    public void reset() {
+        final ObjectActionParameter actionParameter = parameterMemento.getActionParameter(
+                getSpecificationLoader());
+        final ManagedObject parentAdapter =
+                getParentEntityModel().load();
+        final ManagedObject defaultAdapter = actionParameter.getDefault(parentAdapter);
+        setObject(defaultAdapter);
+    }
+
+    @Override
+    public ManagedObject load() {
+        final ActionParameterMemento parameterMemento = getParameterMemento();
+        final ObjectActionParameter actionParameter = parameterMemento
+                .getActionParameter(getSpecificationLoader());
+        final ManagedObject objectAdapter = loadFromSuper();
+
+        if(objectAdapter != null) {
+            return objectAdapter;
+        }
+        if(actionParameter.getFeatureType() == FeatureType.ACTION_PARAMETER_SCALAR) {
+            return objectAdapter;
+        }
+
+
+        // hmmm... I think we should simply return null, as an indicator that there is no "pending" (see ScalarModelWithMultiPending)
+
+        //                // return an empty collection
+        //                // TODO: this should probably move down into OneToManyActionParameter impl
+        //                final OneToManyActionParameter otmap = (OneToManyActionParameter) actionParameter;
+        //                final CollectionSemantics collectionSemantics = otmap.getCollectionSemantics();
+        //                final TypeOfFacet typeOfFacet = actionParameter.getFacet(TypeOfFacet.class);
+        //                final Class<?> elementType = typeOfFacet.value();
+        //                final Object emptyCollection = collectionSemantics.emptyCollectionOf(elementType);
+        //                return scalarModel.getCurrentSession().getPersistenceSession().adapterFor(emptyCollection);
+
+        return objectAdapter;
+
+    }
+
+    @Override
+    public boolean isCollection() {
+        final ActionParameterMemento parameterMemento = getParameterMemento();
+        final ObjectActionParameter actionParameter = parameterMemento.getActionParameter(getSpecificationLoader());
+        return actionParameter.getFeatureType() == FeatureType.ACTION_PARAMETER_COLLECTION;
+    }
+
+    @Override
+    public String toStringOf() {
+        return getName() + ": " + getParameterMemento().toString();
+    }
+
+    // pending args helper
+    private <T> T withPendingParamsDo(
+            @NonNull final Can<ManagedObject> pendingArgs,
+            final BiFunction<PendingParameterModel, ObjectActionParameter, T> function) {
+        val parameterMemento = getParameterMemento();
+        val actionParameter = parameterMemento.getActionParameter(getSpecificationLoader());
+        val actionOwner = getParentEntityModel().load();
+        val pendingParamsModel = actionParameter.getAction().newPendingParameterModelHead(actionOwner)
+                .model(pendingArgs);
+        return function.apply(pendingParamsModel, actionParameter);
+    }
+    
+    @Override
+    protected List<ObjectAction> calcAssociatedActions() {
+        return Collections.emptyList();
+    }
+}
diff --git a/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarPropertyModel.java b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarPropertyModel.java
new file mode 100644
index 0000000..92f08aa
--- /dev/null
+++ b/viewers/wicket/model/src/main/java/org/apache/isis/viewer/wicket/model/models/ScalarPropertyModel.java
@@ -0,0 +1,378 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package org.apache.isis.viewer.wicket.model.models;
+
+import java.util.List;
+
+import org.apache.isis.applib.annotation.Where;
+import org.apache.isis.core.commons.collections.Can;
+import org.apache.isis.core.metamodel.consent.Consent;
+import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
+import org.apache.isis.core.metamodel.facetapi.Facet;
+import org.apache.isis.core.metamodel.facetapi.FacetHolder;
+import org.apache.isis.core.metamodel.facets.object.parseable.ParseableFacet;
+import org.apache.isis.core.metamodel.facets.object.viewmodel.ViewModelFacet;
+import org.apache.isis.core.metamodel.facets.objectvalue.fileaccept.FileAcceptFacet;
+import org.apache.isis.core.metamodel.facets.objectvalue.typicallen.TypicalLengthFacet;
+import org.apache.isis.core.metamodel.facets.value.bigdecimal.BigDecimalValueFacet;
+import org.apache.isis.core.metamodel.facets.value.string.StringValueSemanticsProvider;
+import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ObjectSpecId;
+import org.apache.isis.core.metamodel.spec.ObjectSpecification;
+import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
+import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
+import org.apache.isis.core.webapp.context.memento.ObjectMemento;
+import org.apache.isis.viewer.wicket.model.mementos.PropertyMemento;
+
+import lombok.Getter;
+import lombok.val;
+
+public class ScalarPropertyModel extends ScalarModel {
+    
+    private static final long serialVersionUID = 1L;
+    
+    @Getter private final PropertyMemento propertyMemento;
+
+    /**
+     * Creates a model representing a property of a parent object, with the
+     * {@link #getObject() value of this model} to be current value of the
+     * property.
+     */
+    public ScalarPropertyModel(
+            EntityModel parentEntityModel, 
+            PropertyMemento pm,
+            EntityModel.Mode mode, 
+            EntityModel.RenderingHint renderingHint) {
+        
+        super(parentEntityModel, pm, mode, renderingHint);
+        this.propertyMemento = pm;
+        reset();
+        getAndStore(parentEntityModel);
+    }
+    
+    private void getAndStore(final EntityModel parentEntityModel) {
+        final ObjectMemento parentAdapterMemento = parentEntityModel.getObjectAdapterMemento();
+        final OneToOneAssociation property = propertyMemento.getProperty(getSpecificationLoader());
+        final ManagedObject parentAdapter = super.getCommonContext().reconstructObject(parentAdapterMemento); 
+        setObjectFromPropertyIfVisible(ScalarPropertyModel.this, property, parentAdapter);
+    }
+    
+
+    @Override
+    public String getName() {
+        return getPropertyMemento().getProperty(getSpecificationLoader()).getName();
+    }
+
+    @Override
+    public ObjectSpecification getScalarTypeSpec() {
+        ObjectSpecId type = getPropertyMemento().getType();
+        return getSpecificationLoader().lookupBySpecIdElseLoad(type);
+    }
+
+    @Override
+    public String getIdentifier() {
+        return getPropertyMemento().getIdentifier();
+    }
+
+    @Override
+    public String getCssClass() {
+        final String objectSpecId =
+                getParentEntityModel().getTypeOfSpecification().getSpecId().asString().replace(".", "-");
+        final String propertyId = getIdentifier();
+        return "isis-" + objectSpecId + "-" + propertyId;
+    }
+
+    @Override
+    public boolean whetherHidden(final Where where) {
+        final ManagedObject parentAdapter = getParentEntityModel().load();
+        final OneToOneAssociation property = getPropertyMemento().getProperty(getSpecificationLoader());
+        try {
+            final Consent visibility = property.isVisible(parentAdapter, InteractionInitiatedBy.USER, where);
+            return visibility.isVetoed();
+        } catch (final Exception ex) {
+            return true; // will be hidden
+        }
+    }
+
+    @Override
+    public String whetherDisabled(final Where where) {
+        final ManagedObject parentAdapter = getParentEntityModel().load();
+        final OneToOneAssociation property = getPropertyMemento().getProperty(getSpecificationLoader());
+        try {
+            final Consent usable = property.isUsable(parentAdapter, InteractionInitiatedBy.USER, where);
+            return usable.isAllowed() ? null : usable.getReason();
+        } catch (final Exception ex) {
+            return ex.getLocalizedMessage();
+        }
+    }
+
+    @Override
+    public String parseAndValidate(final String proposedPojoAsStr) {
+        final OneToOneAssociation property = getPropertyMemento().getProperty(getSpecificationLoader());
+        ParseableFacet parseableFacet = property.getFacet(ParseableFacet.class);
+        if (parseableFacet == null) {
+            parseableFacet = property.getSpecification().getFacet(ParseableFacet.class);
+        }
+        try {
+            final ManagedObject parentAdapter = getParentEntityModel().load();
+            final ManagedObject currentValue = property.get(parentAdapter, InteractionInitiatedBy.USER);
+            final ManagedObject proposedAdapter =
+                    parseableFacet.parseTextEntry(currentValue, proposedPojoAsStr, InteractionInitiatedBy.USER);
+            final Consent valid = property.isAssociationValid(parentAdapter, proposedAdapter,
+                    InteractionInitiatedBy.USER);
+            return valid.isAllowed() ? null : valid.getReason();
+//        } catch (final ConcurrencyException ex) {
+//            // disregard concurrency exceptions because will pick up at the IFormValidator level rather
+//            // than each individual property.
+//            return null;
+        } catch (final Exception ex) {
+            return ex.getLocalizedMessage();
+        }
+    }
+
+    @Override
+    public String validate(final ManagedObject proposedAdapter) {
+        final ManagedObject parentAdapter = getParentEntityModel().load();
+        final OneToOneAssociation property = getPropertyMemento().getProperty(getSpecificationLoader());
+        try {
+            final Consent valid = property.isAssociationValid(parentAdapter, proposedAdapter,
+                    InteractionInitiatedBy.USER);
+            return valid.isAllowed() ? null : valid.getReason();
+        } catch (final Exception ex) {
+            return ex.getLocalizedMessage();
+        }
+    }
+
+    @Override
+    public boolean isRequired() {
+        final FacetHolder facetHolder = getPropertyMemento().getProperty(getSpecificationLoader());
+        return isRequired(facetHolder);
+    }
+
+    @Override
+    public <T extends Facet> T getFacet(final Class<T> facetType) {
+        final FacetHolder facetHolder = getPropertyMemento().getProperty(getSpecificationLoader());
+        return facetHolder.getFacet(facetType);
+    }
+
+    @Override
+    public ManagedObject getDefault(
+            final Can<ManagedObject> pendingArgs /*not used*/) {
+
+        final PropertyMemento propertyMemento = getPropertyMemento();
+        final OneToOneAssociation property = propertyMemento
+                .getProperty(getSpecificationLoader());
+        ManagedObject parentAdapter = getParentEntityModel().load();
+        return property.getDefault(parentAdapter);
+    }
+
+    @Override
+    public boolean hasChoices() {
+        final PropertyMemento propertyMemento = getPropertyMemento();
+        final OneToOneAssociation property = propertyMemento.getProperty(getSpecificationLoader());
+        return property.hasChoices();
+    }
+
+    @Override
+    public Can<ManagedObject> getChoices(
+            final Can<ManagedObject> pendingArgs /*not used*/) { 
+
+        final PropertyMemento propertyMemento = getPropertyMemento();
+        final OneToOneAssociation property = propertyMemento
+                .getProperty(getSpecificationLoader());
+        ManagedObject parentAdapter = getParentEntityModel().load();
+        final Can<ManagedObject> choices = property.getChoices(
+                parentAdapter,
+                InteractionInitiatedBy.USER);
+
+        return choices;
+    }
+
+    @Override
+    public boolean hasAutoComplete() {
+        final PropertyMemento propertyMemento = getPropertyMemento();
+        final OneToOneAssociation property = propertyMemento.getProperty(getSpecificationLoader());
+        return property.hasAutoComplete();
+    }
+
+    @Override
+    public Can<ManagedObject> getAutoComplete(
+            final Can<ManagedObject> pendingArgs, /*not used*/
+            final String searchArg) {
+
+        final PropertyMemento propertyMemento = getPropertyMemento();
+        final OneToOneAssociation property = propertyMemento.getProperty(getSpecificationLoader());
+        final ManagedObject parentAdapter =
+                getParentEntityModel().load();
+        final Can<ManagedObject> choices =
+                property.getAutoComplete(
+                        parentAdapter, 
+                        searchArg,
+                        InteractionInitiatedBy.USER);
+        return choices;
+    }
+
+    @Override
+    public int getAutoCompleteOrChoicesMinLength() {
+
+        if (hasAutoComplete()) {
+            final PropertyMemento propertyMemento = getPropertyMemento();
+            final OneToOneAssociation property = propertyMemento.getProperty(getSpecificationLoader());
+            return property.getAutoCompleteMinLength();
+        } else {
+            return 0;
+        }
+    }
+
+    @Override
+    public String getDescribedAs() {
+        final PropertyMemento propertyMemento = getPropertyMemento();
+        final OneToOneAssociation property = propertyMemento.getProperty(getSpecificationLoader());
+        return property.getDescription();
+    }
+
+    @Override
+    public Integer getLength() {
+        final PropertyMemento propertyMemento = getPropertyMemento();
+        final OneToOneAssociation property = propertyMemento.getProperty(getSpecificationLoader());
+        final BigDecimalValueFacet facet = property.getFacet(BigDecimalValueFacet.class);
+        return facet != null? facet.getPrecision(): null;
+    }
+
+    @Override
+    public Integer getScale() {
+        final PropertyMemento propertyMemento = getPropertyMemento();
+        final OneToOneAssociation property = propertyMemento.getProperty(getSpecificationLoader());
+        final BigDecimalValueFacet facet = property.getFacet(BigDecimalValueFacet.class);
+        return facet != null? facet.getScale(): null;
+    }
+
+    @Override
+    public int getTypicalLength() {
+        final PropertyMemento propertyMemento = getPropertyMemento();
+        final OneToOneAssociation property = propertyMemento.getProperty(getSpecificationLoader());
+        final TypicalLengthFacet facet = property.getFacet(TypicalLengthFacet.class);
+        return facet != null? facet.value() : StringValueSemanticsProvider.TYPICAL_LENGTH;
+    }
+
+    @Override
+    public String getFileAccept() {
+        final PropertyMemento propertyMemento = getPropertyMemento();
+        final OneToOneAssociation property = propertyMemento.getProperty(getSpecificationLoader());
+        final FileAcceptFacet facet = property.getFacet(FileAcceptFacet.class);
+        return facet != null? facet.value(): null;
+    }
+
+    @Override
+    public void reset() {
+        final OneToOneAssociation property = getPropertyMemento().getProperty(getSpecificationLoader());
+
+        val parentAdapter = getParentEntityModel().load();
+
+        setObjectFromPropertyIfVisible(this, property, parentAdapter);
+    }
+
+    @Override
+    public ManagedObject load() {
+        return loadFromSuper();
+    }
+
+    @Override
+    public boolean isCollection() {
+        return false;
+    }
+
+    @Override
+    public String toStringOf() {
+        return getName() + ": " + getPropertyMemento().toString();
+    }
+    
+    public String getReasonInvalidIfAny() {
+        val property = getPropertyMemento().getProperty(getSpecificationLoader());
+        val adapter = getParentEntityModel().load();
+        val associate = getObject();
+        Consent validity = property.isAssociationValid(adapter, associate, InteractionInitiatedBy.USER);
+        return validity.isAllowed() ? null : validity.getReason();
+    }
+    
+    /**
+     * Apply changes to the underlying adapter (possibly returning a new adapter).
+     *
+     * @return adapter, which may be different from the original (if a {@link ViewModelFacet#isCloneable(Object) cloneable} view model, for example.
+     */
+    public ManagedObject applyValue(ManagedObject adapter) {
+        val property = getPropertyMemento().getProperty(getSpecificationLoader());
+
+        //
+        // previously there was a guard here to only apply changes provided:
+        //
+        // property.containsDoOpFacet(NotPersistedFacet.class) == null
+        //
+        // however, that logic is wrong; although a property may not be directly
+        // persisted so far as JDO is concerned, it may be indirectly persisted
+        // as the result of business logic in the setter.
+        //
+        // for example, see ExampleTaggableEntity (in isisaddons-module-tags).
+        //
+
+        //
+        // previously (prior to XML layouts and 'single property' edits) we also used to check if
+        // the property was disabled, using:
+        //
+        // if(property.containsDoOpFacet(DisabledFacet.class)) {
+        //    // skip, as per comments above
+        //    return;
+        // }
+        //
+        // However, this would seem to be wrong, because the presence of a DisabledFacet doesn't necessarily mean
+        // that the property is disabled (its disabledReason(...) might return null).
+        //
+        // In any case, the only code that calls this method already does the check, so think this is safe
+        // to just remove.
+
+        val associate = getObject();
+        property.set(adapter, associate, InteractionInitiatedBy.USER);
+
+        final ViewModelFacet recreatableObjectFacet = adapter.getSpecification().getFacet(ViewModelFacet.class);
+        if(recreatableObjectFacet != null) {
+            final Object viewModel = adapter.getPojo();
+            final boolean cloneable = recreatableObjectFacet.isCloneable(viewModel);
+            if(cloneable) {
+                //XXX lombok issue, no val
+                Object newViewModelPojo = recreatableObjectFacet.clone(viewModel);
+                adapter = super.getPojoToAdapter().apply(newViewModelPojo);
+            }
+        }
+
+        return adapter;
+    }
+    
+    @Override
+    protected List<ObjectAction> calcAssociatedActions() {
+
+        final EntityModel parentEntityModel1 = this.getParentEntityModel();
+        final ManagedObject parentAdapter = parentEntityModel1.load();
+
+        final OneToOneAssociation oneToOneAssociation =
+                this.getPropertyMemento().getProperty(this.getSpecificationLoader());
+
+        return ObjectAction.Util.findForAssociation(parentAdapter, oneToOneAssociation);
+    }
+    
+}
diff --git a/viewers/wicket/model/src/test/java/org/apache/isis/viewer/wicket/model/models/ScalarModel_isScalarSubtypingAnyOf_Test.java b/viewers/wicket/model/src/test/java/org/apache/isis/viewer/wicket/model/models/ScalarModel_isScalarSubtypingAnyOf_Test.java
index ccb8283..be6d00c 100644
--- a/viewers/wicket/model/src/test/java/org/apache/isis/viewer/wicket/model/models/ScalarModel_isScalarSubtypingAnyOf_Test.java
+++ b/viewers/wicket/model/src/test/java/org/apache/isis/viewer/wicket/model/models/ScalarModel_isScalarSubtypingAnyOf_Test.java
@@ -90,7 +90,7 @@ public class ScalarModel_isScalarSubtypingAnyOf_Test {
     }
 
     private ScalarModel newScalarModelFor(final Class<?> result) {
-        val scalarModel = new ScalarModel(mockEntityModel, null) {
+        val scalarModel = new ScalarParameterModel(mockEntityModel, null) {
             private static final long serialVersionUID = 1L;
 
             @Override public ObjectSpecification getTypeOfSpecification() {
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersForm.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersForm.java
index 314a7c2..a0572ac 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersForm.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/actions/ActionParametersForm.java
@@ -39,6 +39,7 @@ import org.apache.isis.viewer.wicket.model.hints.IsisActionCompletedEvent;
 import org.apache.isis.viewer.wicket.model.isis.WicketViewerSettings;
 import org.apache.isis.viewer.wicket.model.models.ActionArgumentModel;
 import org.apache.isis.viewer.wicket.model.models.ActionModel;
+import org.apache.isis.viewer.wicket.model.models.ScalarParameterModel;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelAbstract2;
 import org.apache.isis.viewer.wicket.ui.panels.FormExecutorStrategy;
@@ -166,7 +167,9 @@ class ActionParametersForm extends PromptFormAbstract<ActionModel> {
 
         final ActionModel actionModel = getActionModel();
 
-        final int paramNumberUpdated = scalarPanelUpdated.getModel().getParameterMemento().getNumber();
+        val paramModel = (ScalarParameterModel)scalarPanelUpdated.getModel();
+        
+        final int paramNumberUpdated = paramModel.getParameterMemento().getNumber();
         
         val action = actionModel.getActionMemento().getAction(getSpecificationLoader());
 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditForm.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditForm.java
index 833a571..030c110 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditForm.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditForm.java
@@ -28,31 +28,30 @@ import org.apache.isis.applib.annotation.PromptStyle;
 import org.apache.isis.viewer.wicket.model.hints.IsisPropertyEditCompletedEvent;
 import org.apache.isis.viewer.wicket.model.isis.WicketViewerSettings;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.model.models.ScalarPropertyModel;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
 import org.apache.isis.viewer.wicket.ui.components.scalars.ScalarPanelAbstract2;
 import org.apache.isis.viewer.wicket.ui.panels.FormExecutorStrategy;
 import org.apache.isis.viewer.wicket.ui.panels.PromptFormAbstract;
 
-class PropertyEditForm extends PromptFormAbstract<ScalarModel> {
-
-    private static final long serialVersionUID = 1L;
+import lombok.val;
 
+class PropertyEditForm extends PromptFormAbstract<ScalarPropertyModel> {
 
+    private static final long serialVersionUID = 1L;
 
     public PropertyEditForm(
             final String id,
             final Component parentPanel,
             final WicketViewerSettings settings,
-            final ScalarModel propertyModel) {
+            final ScalarPropertyModel propertyModel) {
         super(id, parentPanel, settings, propertyModel);
     }
 
-    private ScalarModel getScalarModel() {
-        return (ScalarModel) super.getModel();
+    private ScalarPropertyModel getScalarModel() {
+        return (ScalarPropertyModel) super.getModel();
     }
 
-
-
     @Override
     protected void addParameters() {
         final ScalarModel scalarModel = getScalarModel();
@@ -107,8 +106,8 @@ class PropertyEditForm extends PromptFormAbstract<ScalarModel> {
     }
 
     @Override
-    protected FormExecutorStrategy<ScalarModel> getFormExecutorStrategy() {
-        ScalarModel scalarModel = getScalarModel();
+    protected FormExecutorStrategy<ScalarPropertyModel> getFormExecutorStrategy() {
+        val scalarModel = getScalarModel();
         return new PropertyFormExecutorStrategy(scalarModel);
     }
 }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditFormPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditFormPanel.java
index 0465c8e..da74de6 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditFormPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditFormPanel.java
@@ -19,7 +19,7 @@
 
 package org.apache.isis.viewer.wicket.ui.components.property;
 
-import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.model.models.ScalarPropertyModel;
 import org.apache.isis.viewer.wicket.ui.components.actions.ActionParametersFormPanel;
 import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
 import org.apache.isis.viewer.wicket.ui.panels.PromptFormPanelAbstract;
@@ -33,19 +33,19 @@ import org.apache.isis.viewer.wicket.ui.panels.PromptFormPanelAbstract;
  * </p>
  */
 public class PropertyEditFormPanel
-extends PromptFormPanelAbstract<ScalarModel> {
+extends PromptFormPanelAbstract<ScalarPropertyModel> {
 
     private static final long serialVersionUID = 1L;
 
     static final String ID_PROPERTY = "property";
 
-    public PropertyEditFormPanel(final String id, final ScalarModel model) {
+    public PropertyEditFormPanel(final String id, final ScalarPropertyModel model) {
         super(id, model);
         buildGui();
     }
 
     private void buildGui() {
-        ScalarModel model = getModel();
+        ScalarPropertyModel model = getModel();
         add(new PropertyEditForm("inputForm", this, this.getWicketViewerSettings(), model));
     }
 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditFormPanelFactory.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditFormPanelFactory.java
index 50ecbf6..9f95084 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditFormPanelFactory.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditFormPanelFactory.java
@@ -22,7 +22,7 @@ package org.apache.isis.viewer.wicket.ui.components.property;
 import org.apache.wicket.Component;
 import org.apache.wicket.model.IModel;
 
-import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.model.models.ScalarPropertyModel;
 import org.apache.isis.viewer.wicket.ui.ComponentFactory;
 import org.apache.isis.viewer.wicket.ui.ComponentFactoryAbstract;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
@@ -40,12 +40,12 @@ public class PropertyEditFormPanelFactory extends ComponentFactoryAbstract {
 
     @Override
     public ApplicationAdvice appliesTo(final IModel<?> model) {
-        return appliesIf(model instanceof ScalarModel);
+        return appliesIf(model instanceof ScalarPropertyModel);
     }
 
     @Override
     public Component createComponent(final String id, final IModel<?> model) {
-        final ScalarModel scalarModel = (ScalarModel) model;
+        final ScalarPropertyModel scalarModel = (ScalarPropertyModel) model;
         return new PropertyEditFormPanel(id, scalarModel);
     }
 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPanel.java
index 78888f0..59ead05 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPanel.java
@@ -27,6 +27,7 @@ import org.apache.isis.core.metamodel.facets.all.named.NamedFacet;
 import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.model.models.ScalarPropertyModel;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
 import org.apache.isis.viewer.wicket.ui.components.actions.ActionParametersPanel;
 import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
@@ -34,7 +35,7 @@ import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
 /**
  * Corresponding component to prompt for action (parameters) is {@link ActionParametersPanel}.
  */
-public class PropertyEditPanel extends PanelAbstract<ScalarModel> {
+public class PropertyEditPanel extends PanelAbstract<ScalarPropertyModel> {
 
     private static final long serialVersionUID = 1L;
 
@@ -49,8 +50,8 @@ public class PropertyEditPanel extends PanelAbstract<ScalarModel> {
 
     public PropertyEditPanel(
             final String id,
-            final ScalarModel scalarModel) {
-        super(id, new ScalarModel(scalarModel.getParentEntityModel(), scalarModel.getPropertyMemento(),
+            final ScalarPropertyModel scalarModel) {
+        super(id, new ScalarPropertyModel(scalarModel.getParentEntityModel(), scalarModel.getPropertyMemento(),
                 EntityModel.Mode.EDIT, EntityModel.RenderingHint.REGULAR));
 
         buildGui(scalarModel);
@@ -67,7 +68,7 @@ public class PropertyEditPanel extends PanelAbstract<ScalarModel> {
         buildGuiForParameters(scalarModel);
     }
 
-    ScalarModel getScalarModel() {
+    ScalarPropertyModel getScalarModel() {
         return super.getModel();
     }
 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPanelFactory.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPanelFactory.java
index a5b8076..5f8dd7d 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPanelFactory.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyEditPanelFactory.java
@@ -22,7 +22,7 @@ package org.apache.isis.viewer.wicket.ui.components.property;
 import org.apache.wicket.Component;
 import org.apache.wicket.model.IModel;
 
-import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.model.models.ScalarPropertyModel;
 import org.apache.isis.viewer.wicket.ui.ComponentFactory;
 import org.apache.isis.viewer.wicket.ui.ComponentFactoryAbstract;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
@@ -40,12 +40,12 @@ public class PropertyEditPanelFactory extends ComponentFactoryAbstract {
 
     @Override
     public ApplicationAdvice appliesTo(final IModel<?> model) {
-        return appliesIf(model instanceof ScalarModel);
+        return appliesIf(model instanceof ScalarPropertyModel);
     }
 
     @Override
     public Component createComponent(final String id, final IModel<?> model) {
-        final ScalarModel scalarModel = (ScalarModel) model;
+        final ScalarPropertyModel scalarModel = (ScalarPropertyModel) model;
         return new PropertyEditPanel(id, scalarModel);
     }
 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyFormExecutorStrategy.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyFormExecutorStrategy.java
index 24841f1..894390d 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyFormExecutorStrategy.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/property/PropertyFormExecutorStrategy.java
@@ -22,22 +22,22 @@ import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.request.cycle.RequestCycle;
 
 import org.apache.isis.core.metamodel.spec.ManagedObject;
-import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.model.models.ScalarPropertyModel;
 import org.apache.isis.viewer.wicket.ui.pages.entity.EntityPage;
 import org.apache.isis.viewer.wicket.ui.panels.FormExecutorStrategy;
 
 import lombok.val;
 
-public class PropertyFormExecutorStrategy implements FormExecutorStrategy<ScalarModel> {
+public class PropertyFormExecutorStrategy implements FormExecutorStrategy<ScalarPropertyModel> {
 
-    private final ScalarModel model;
+    private final ScalarPropertyModel model;
 
-    public PropertyFormExecutorStrategy(final ScalarModel scalarModel) {
+    public PropertyFormExecutorStrategy(final ScalarPropertyModel scalarModel) {
         model = scalarModel;
     }
 
     @Override
-    public ScalarModel getModel() {
+    public ScalarPropertyModel getModel() {
         return model;
     }
 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/propertyheader/PropertyEditPromptHeaderPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/propertyheader/PropertyEditPromptHeaderPanel.java
index b084d86..507202c 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/propertyheader/PropertyEditPromptHeaderPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/propertyheader/PropertyEditPromptHeaderPanel.java
@@ -24,18 +24,18 @@ import org.apache.wicket.model.IModel;
 import org.apache.isis.core.metamodel.facets.all.named.NamedFacet;
 import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
-import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.model.models.ScalarPropertyModel;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
 import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
 
 import lombok.val;
 
-public class PropertyEditPromptHeaderPanel extends PanelAbstract<ScalarModel> {
+public class PropertyEditPromptHeaderPanel extends PanelAbstract<ScalarPropertyModel> {
 
     private static final long serialVersionUID = 1L;
     private static final String ID_PROPERTY_NAME = "propertyName";
 
-    public PropertyEditPromptHeaderPanel(String id, final ScalarModel model) {
+    public PropertyEditPromptHeaderPanel(String id, final ScalarPropertyModel model) {
         super(id, model);
 
         val targetAdapter = model.getParentEntityModel().load();
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
index 3f20003..5d40103 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract.java
@@ -60,8 +60,8 @@ import lombok.val;
  *     It is however still used by some wicket addons (specifically, pdfjs).
  * </p>
  */
-public abstract class ScalarPanelAbstract 
-extends PanelAbstract<ScalarModel> 
+public abstract class ScalarPanelAbstract<T extends ScalarModel> 
+extends PanelAbstract<T> 
 implements ScalarModelProvider {
 
     private static final long serialVersionUID = 1L;
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract2.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract2.java
index 039cc1b..dbec3d0 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract2.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelAbstract2.java
@@ -53,6 +53,7 @@ import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectAction;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
+import org.apache.isis.core.metamodel.specloader.specimpl.PendingParameterModel;
 import org.apache.isis.viewer.wicket.model.links.LinkAndLabel;
 import org.apache.isis.viewer.wicket.model.mementos.ActionParameterMemento;
 import org.apache.isis.viewer.wicket.model.models.ActionModel;
@@ -61,6 +62,7 @@ import org.apache.isis.viewer.wicket.model.models.ActionPromptProvider;
 import org.apache.isis.viewer.wicket.model.models.EntityModel;
 import org.apache.isis.viewer.wicket.model.models.InlinePromptContext;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.model.models.ScalarPropertyModel;
 import org.apache.isis.viewer.wicket.ui.ComponentType;
 import org.apache.isis.viewer.wicket.ui.components.actionmenu.entityactions.AdditionalLinksPanel;
 import org.apache.isis.viewer.wicket.ui.components.actionmenu.entityactions.LinkAndLabelUtil;
@@ -132,12 +134,14 @@ implements ScalarModelSubscriber2 {
     public Repaint updateIfNecessary(
             final ActionModel actionModel,
             final int paramNumUpdated,
-            final int paramNumToPossiblyUpdate,
+            final int paramNumToPossiblyUpdate,//FIXME I guess we need to re-rerender all not just the next
             final AjaxRequestTarget target) {
 
         final ObjectAction action = actionModel.getActionMemento().getAction(getSpecificationLoader());
-        final Can<ManagedObject> pendingArguments = actionModel.getArgumentsAsImmutable();
-
+        final PendingParameterModel pendingArguments = actionModel.getArgumentsAsParamModel();
+        final Can<ManagedObject> pendingArgumentsReadonly = pendingArguments.getParamValues();
+        
+        
         // could almost certainly simplify this... (used by visibility and usability checks)
         final ObjectActionParameter actionParameter = action.getParameters().getElseFail(paramNumToPossiblyUpdate);
         val targetAdapter = actionModel.getTargetAdapter();
@@ -145,7 +149,7 @@ implements ScalarModelSubscriber2 {
 
         // check visibility
         final Consent visibilityConsent = actionParameter
-                .isVisible(realTargetAdapter, pendingArguments, InteractionInitiatedBy.USER);
+                .isVisible(realTargetAdapter, pendingArgumentsReadonly, InteractionInitiatedBy.USER);
 
         final boolean visibilityBefore = isVisible();
         final boolean visibilityAfter = visibilityConsent.isAllowed();
@@ -154,7 +158,7 @@ implements ScalarModelSubscriber2 {
 
         // check usability
         final Consent usabilityConsent = actionParameter
-                .isUsable(realTargetAdapter, pendingArguments, InteractionInitiatedBy.USER);
+                .isUsable(realTargetAdapter, pendingArgumentsReadonly, InteractionInitiatedBy.USER);
 
         final boolean usabilityBefore = isEnabled();
         final boolean usabilityAfter = usabilityConsent.isAllowed();
@@ -167,13 +171,12 @@ implements ScalarModelSubscriber2 {
         // even if now invisible or unusable, we recalculate args and ensure compatible
         // (else can hit complicated edge cases with stale data when next re-enable/make visible)
         final ScalarModel model = getModel();
-        val defaultIfAny = model.getKind()
-                .getDefault(scalarModel, pendingArguments);
+        val defaultIfAny = model.getDefault(pendingArgumentsReadonly);
 
         val actionParameterMemento = new ActionParameterMemento(actionParameter);
         val actionArgumentModel = actionModel.getArgumentModel(actionParameterMemento);
 
-        val pendingArg = pendingArguments.getElseFail(paramNumToPossiblyUpdate);
+        val pendingArg = pendingArgumentsReadonly.getElseFail(paramNumToPossiblyUpdate);
         
         if (defaultIfAny != null) {
             scalarModel.setObject(defaultIfAny);
@@ -183,11 +186,11 @@ implements ScalarModelSubscriber2 {
 
             boolean shouldBlankout = false;
             
-            if(pendingArg != null) {
+            if(ManagedObject.isNullOrUnspecifiedOrEmpty(pendingArg)) {
                 if(scalarModel.hasChoices()) {
                     // make sure the object is one of the choices, else blank it out.
                     val choices = scalarModel
-                            .getChoices(pendingArguments);
+                            .getChoices(pendingArgumentsReadonly);
                     
                     shouldBlankout = 
                             ! isPartOfChoicesConsideringDependentArgs(scalarModel, pendingArg, choices);
@@ -375,11 +378,11 @@ implements ScalarModelSubscriber2 {
         scalarTypeContainer.addOrReplace(scalarIfCompact, scalarIfRegular);
 
         // find associated actions for this scalar property (only properties will have any.)
-        final ScalarModel.AssociatedActions associatedActionsIfProperty =
-                scalarModel.associatedActionsIfProperty();
+        final ScalarModel.AssociatedActions associatedActions =
+                scalarModel.getAssociatedActions(); 
         final ObjectAction inlineActionIfAny =
-                associatedActionsIfProperty.getFirstAssociatedWithInlineAsIfEdit();
-        final List<ObjectAction> remainingAssociated = associatedActionsIfProperty.getRemainingAssociated();
+                associatedActions.getFirstAssociatedWithInlineAsIfEdit();
+        final List<ObjectAction> remainingAssociated = associatedActions.getRemainingAssociated();
 
         // convert those actions into UI layer widgets
         final List<LinkAndLabel> linkAndLabels  = LinkAndLabelUtil.asActionLinks(this.scalarModel, remainingAssociated);
@@ -868,8 +871,9 @@ implements ScalarModelSubscriber2 {
                     final ActionPrompt prompt = ActionPromptProvider
                             .getFrom(ScalarPanelAbstract2.this).getActionPrompt(promptStyle, sort);
 
-                    PropertyEditPromptHeaderPanel titlePanel = new PropertyEditPromptHeaderPanel(prompt.getTitleId(),
-                            ScalarPanelAbstract2.this.scalarModel);
+                    PropertyEditPromptHeaderPanel titlePanel = new PropertyEditPromptHeaderPanel(
+                            prompt.getTitleId(),
+                            (ScalarPropertyModel)ScalarPanelAbstract2.this.scalarModel);
 
                     final PropertyEditPanel propertyEditPanel =
                             (PropertyEditPanel) getComponentFactoryRegistry().createComponent(
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelSelect2Abstract.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelSelect2Abstract.java
index a389203..be8a972 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelSelect2Abstract.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/ScalarPanelSelect2Abstract.java
@@ -37,6 +37,7 @@ import org.apache.isis.core.metamodel.spec.ManagedObject;
 import org.apache.isis.core.webapp.context.memento.ObjectMemento;
 import org.apache.isis.viewer.wicket.model.models.ActionModel;
 import org.apache.isis.viewer.wicket.model.models.ScalarModel;
+import org.apache.isis.viewer.wicket.model.models.ScalarParameterModel;
 import org.apache.isis.viewer.wicket.ui.components.widgets.bootstrap.FormGroup;
 import org.apache.isis.viewer.wicket.ui.components.widgets.select2.Select2;
 import org.apache.isis.viewer.wicket.ui.components.widgets.select2.providers.ObjectAdapterMementoProviderAbstract;
@@ -58,7 +59,10 @@ public abstract class ScalarPanelSelect2Abstract extends ScalarPanelAbstract2 {
 
     protected Select2 createSelect2(final String id) {
         final Select2 select2 = Select2.createSelect2(id, scalarModel);
-        setProviderAndCurrAndPending(select2, scalarModel.getActionArgsHint());
+        setProviderAndCurrAndPending(select2, 
+                (scalarModel instanceof ScalarParameterModel)
+                    ? ((ScalarParameterModel)scalarModel).getActionArgsHint()
+                    : null);
         select2.setRequired(scalarModel.isRequired());
         return select2;
     }