You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by ah...@apache.org on 2021/12/20 09:16:55 UTC

[isis] branch master updated: ISIS-2882: allow bindable values to install a guard against invalid values

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 2d5138f  ISIS-2882: allow bindable values to install a guard against invalid values
2d5138f is described below

commit 2d5138f9f63f0cf8ed7d3f37a36cd583896b7168
Author: Andi Huber <ah...@apache.org>
AuthorDate: Mon Dec 20 10:16:48 2021 +0100

    ISIS-2882: allow bindable values to install a guard against invalid
    values
---
 .../internal/binding/_BindableAbstract.java        | 10 ++++++++-
 .../interactions/managed/ManagedProperty.java      |  4 ++--
 .../interactions/managed/ManagedValue.java         |  8 +++++--
 .../managed/ParameterNegotiationModel.java         |  2 ++
 .../managed/PropertyNegotiationModel.java          |  1 +
 .../isis/core/metamodel/spec/ManagedObjects.java   | 26 +++++++++++++++++++---
 .../core/metamodel/spec/feature/ObjectFeature.java |  3 ++-
 .../core/runtime/context/IsisAppCommonContext.java |  4 ----
 .../actionresponse/ActionResultResponseType.java   |  2 +-
 .../ui/components/scalars/TextFieldValueModel.java |  2 +-
 .../blobclob/IsisBlobOrClobPanelAbstract.java      |  2 +-
 .../components/scalars/primitive/BooleanPanel.java |  4 ++--
 12 files changed, 50 insertions(+), 18 deletions(-)

diff --git a/commons/src/main/java/org/apache/isis/commons/internal/binding/_BindableAbstract.java b/commons/src/main/java/org/apache/isis/commons/internal/binding/_BindableAbstract.java
index 29271ca..4533496 100644
--- a/commons/src/main/java/org/apache/isis/commons/internal/binding/_BindableAbstract.java
+++ b/commons/src/main/java/org/apache/isis/commons/internal/binding/_BindableAbstract.java
@@ -59,6 +59,13 @@ public abstract class _BindableAbstract<T> implements Bindable<T> {
      */
     @Setter private @NonNull UnaryOperator<T> valueRefiner = UnaryOperator.identity();
 
+    /**
+     * Called within {@link #setValue()} to guard against invalid new values.
+     * <p>
+     * use-case: guard against incompatible types
+     */
+    @Setter private @NonNull UnaryOperator<T> valueGuard = UnaryOperator.identity();
+
     public _BindableAbstract() {
     }
 
@@ -106,10 +113,11 @@ public abstract class _BindableAbstract<T> implements Bindable<T> {
     }
 
     @Override
-    public void setValue(final T newValue) {
+    public void setValue(final T proposedNewValue) {
         if (isBound()) {
             throw _Exceptions.unrecoverable("Cannot set value on a bound bindable.");
         }
+        val newValue = valueGuard.apply(proposedNewValue);
         if (value != newValue) {
             value = newValue;
             markInvalid();
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedProperty.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedProperty.java
index a454931..90566e9 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedProperty.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedProperty.java
@@ -124,8 +124,8 @@ extends ManagedMember {
             return interactionVeto;
         }
 
-        ManagedObject managedObject = property.set(getOwner(), proposedNewValue, InteractionInitiatedBy.USER);
-        setOwner(managedObject);
+        val updatedOwner = property.set(getOwner(), proposedNewValue, InteractionInitiatedBy.USER);
+        setOwner(updatedOwner);
         observablePropValue.invalidate();
         return Optional.empty();
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedValue.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedValue.java
index d261c01..ae5cf21 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedValue.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ManagedValue.java
@@ -43,13 +43,17 @@ public interface ManagedValue {
     Observable<Can<ManagedObject>> getChoices();
 
     default void update(final UnaryOperator<ManagedObject> updater) {
-        val value = getValue();
-        value.setValue(updater.apply(value.getValue()));
+        val valueHolder = getValue();
+        val oldValue = valueHolder.getValue();
+        val newValue = updater.apply(oldValue);
+        valueHolder.setValue(newValue);
     }
 
     /**
      * Requires specified objects, that is ManagedObjects require an ObjectSpecification.
+     * @deprecated does not preserve memoized bookmarks; use for testing only!
      */
+    @Deprecated
     default void updatePojo(final UnaryOperator<Object> updater) {
         update(v->ManagedObject.of(v.getSpecification(), updater.apply(v.getPojo())));
     }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ParameterNegotiationModel.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ParameterNegotiationModel.java
index e9617d9..95b3756 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ParameterNegotiationModel.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/ParameterNegotiationModel.java
@@ -38,6 +38,7 @@ import org.apache.isis.core.metamodel.consent.Consent;
 import org.apache.isis.core.metamodel.consent.InteractionInitiatedBy;
 import org.apache.isis.core.metamodel.consent.InteractionResult;
 import org.apache.isis.core.metamodel.spec.ManagedObject;
+import org.apache.isis.core.metamodel.spec.ManagedObjects;
 import org.apache.isis.core.metamodel.spec.ManagedObjects.EntityUtil;
 import org.apache.isis.core.metamodel.spec.ObjectSpecification;
 import org.apache.isis.core.metamodel.spec.feature.ObjectActionParameter;
@@ -277,6 +278,7 @@ public class ParameterNegotiationModel {
 
             bindableParamValue = _Bindables.forValue(initialValue);
             bindableParamValue.setValueRefiner(EntityUtil::refetch);
+            bindableParamValue.setValueGuard(ManagedObjects.assertInstanceOf(metaModel.getElementType()));
             bindableParamValue.addListener((e,o,n)->{
                 if(n==null) {
                     // lift null to empty ...
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/PropertyNegotiationModel.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/PropertyNegotiationModel.java
index bba953d..8e775f6 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/PropertyNegotiationModel.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/interactions/managed/PropertyNegotiationModel.java
@@ -63,6 +63,7 @@ public class PropertyNegotiationModel implements ManagedValue {
 
         proposedValue = _Bindables.forValue(defaultValue);
         proposedValue.setValueRefiner(EntityUtil::refetch);
+        proposedValue.setValueGuard(ManagedObjects.assertInstanceOf(propMeta.getElementType()));
         proposedValue.addListener((e,o,n)->{
             invalidateChoicesAndValidation();
         });
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObjects.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObjects.java
index b312869..fd05830 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObjects.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/ManagedObjects.java
@@ -123,6 +123,29 @@ public final class ManagedObjects {
                 .map(ObjectSpecification::getLogicalTypeName);
     }
 
+    // -- INSTANCE-OF CHECKS
+
+    /**
+     * guard against incompatible type
+     */
+    public static @NonNull UnaryOperator<ManagedObject> assertInstanceOf(final ObjectSpecification elementType) {
+        val upperBound = elementType.getCorrespondingClass();
+        return newValue -> {
+            if(ManagedObjects.isNullOrUnspecifiedOrEmpty(newValue)) {
+                return newValue;
+            }
+            val newValueActualType = newValue.getSpecification().getCorrespondingClass();
+            if(!upperBound.isAssignableFrom(newValueActualType)) {
+                throw _Exceptions.illegalArgument("Proposed new value has incompatible type %s,"
+                        + "must be an instance of %s.",
+                        newValueActualType.getName(),
+                        upperBound.getName());
+            }
+            return newValue;
+        };
+    }
+
+
     // -- IDENTIFICATION
 
     public static Optional<ObjectSpecification> spec(final @Nullable ManagedObject managedObject) {
@@ -1063,7 +1086,4 @@ public final class ManagedObjects {
 
     }
 
-
-
-
 }
diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectFeature.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectFeature.java
index 70d797b..956694a 100644
--- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectFeature.java
+++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/spec/feature/ObjectFeature.java
@@ -155,8 +155,9 @@ public interface ObjectFeature extends Specification {
      * element the collection holds (not the type of collection).
      * <li>for an {@link ObjectAction action} will return {@link ObjectAction#getReturnType()}.
      * <li>for an {@link ObjectActionParameter action parameter}, will return the type of
-     * the parameter}.
+     * the parameter.
      * </ul>
+     * @since 2.0
      */
     ObjectSpecification getElementType();
 
diff --git a/core/runtime/src/main/java/org/apache/isis/core/runtime/context/IsisAppCommonContext.java b/core/runtime/src/main/java/org/apache/isis/core/runtime/context/IsisAppCommonContext.java
index bc4bead..ddf57ca 100644
--- a/core/runtime/src/main/java/org/apache/isis/core/runtime/context/IsisAppCommonContext.java
+++ b/core/runtime/src/main/java/org/apache/isis/core/runtime/context/IsisAppCommonContext.java
@@ -19,7 +19,6 @@
 package org.apache.isis.core.runtime.context;
 
 import java.util.Optional;
-import java.util.function.Function;
 import java.util.function.Supplier;
 
 import org.springframework.lang.Nullable;
@@ -76,9 +75,6 @@ public class IsisAppCommonContext implements HasMetaModelContext {
     @Getter(lazy = true, value = AccessLevel.PRIVATE)
     private final ObjectMementoService mementoService = lookupServiceElseFail(ObjectMementoService.class);
 
-    @Getter(lazy = true)
-    private final Function<Object, ManagedObject> pojoToAdapter = metaModelContext.getObjectManager()::adapt;
-
     public Optional<MessageBroker> getMessageBroker() {
         return getMetaModelContext().getServiceRegistry().lookupService(MessageBroker.class);
     }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseType.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseType.java
index cbe0018..fc8bf04 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseType.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/actionresponse/ActionResultResponseType.java
@@ -251,7 +251,7 @@ public enum ActionResultResponseType {
                     .findFirst()
                     .orElseThrow(_Exceptions::noSuchElement);
 
-            final var scalarAdapter = commonContext.getPojoToAdapter().apply(pojo);
+            final var scalarAdapter = commonContext.getObjectManager().adapt(pojo);
             return scalarAdapter;
         }
     }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/TextFieldValueModel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/TextFieldValueModel.java
index 340b7c6..15e9836 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/TextFieldValueModel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/TextFieldValueModel.java
@@ -66,7 +66,7 @@ public class TextFieldValueModel<T extends Serializable> extends Model<T> {
         if (object == null) {
             scalarModel.setObject(null);
         } else {
-            val objectAdapter = scalarModel.getCommonContext().getPojoToAdapter().apply(object);
+            val objectAdapter = scalarModel.getCommonContext().getObjectManager().adapt(object);
             scalarModel.setObject(objectAdapter);
         }
     }
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/IsisBlobOrClobPanelAbstract.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/IsisBlobOrClobPanelAbstract.java
index 8ad5463..9210858 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/IsisBlobOrClobPanelAbstract.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/blobclob/IsisBlobOrClobPanelAbstract.java
@@ -186,7 +186,7 @@ extends ScalarPanelAbstract {
                         }
 
                         val blob = getBlobOrClobFrom(fileUploads);
-                        val objectAdapter = scalarModel.getCommonContext().getPojoToAdapter().apply(blob);
+                        val objectAdapter = scalarModel.getCommonContext().getObjectManager().adapt(blob);
                         getModel().setObject(objectAdapter);
                     }
 
diff --git a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/BooleanPanel.java b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/BooleanPanel.java
index 9f0e2e7..047639d 100644
--- a/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/BooleanPanel.java
+++ b/viewers/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/primitive/BooleanPanel.java
@@ -139,7 +139,7 @@ public class BooleanPanel extends ScalarPanelAbstract {
 
             @Override
             public void setObject(final Boolean object) {
-                val objectAdapter = scalarModel.getCommonContext().getPojoToAdapter().apply(object);
+                val objectAdapter = scalarModel.getCommonContext().getObjectManager().adapt(object);
                 getModel().setObject(objectAdapter);
             }
         }) {
@@ -178,7 +178,7 @@ public class BooleanPanel extends ScalarPanelAbstract {
         final ObjectSpecification objectSpecification = getModel().getScalarTypeSpec();
         if(objectSpecification.getFullIdentifier().equals("boolean")) {
             if(getModel().getObject() == null) {
-                val objectAdapter = scalarModel.getCommonContext().getPojoToAdapter().apply(Boolean.FALSE);
+                val objectAdapter = scalarModel.getCommonContext().getObjectManager().adapt(Boolean.FALSE);
                 getModel().setObject(objectAdapter);
             }
         }